{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from torch.optim.lr_scheduler import StepLR\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from mpl_toolkits.mplot3d import Axes3D\n",
    "from matplotlib import cm\n",
    "import os\n",
    "from pyDOE import lhs\n",
    "import shutil"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Solving PDEs based on Neural Networks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## PDE"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Consider Poisson equation\n",
    "$$\n",
    "\\left\\{\n",
    "\\begin{array}{rl}\n",
    "-\\nabla \\cdot a \\nabla u(\\boldsymbol x) = f(\\boldsymbol x), & \\boldsymbol x \\in \\Omega\\\\\n",
    "u(\\boldsymbol x) = g(\\boldsymbol x), & \\boldsymbol x \\in \\partial \\Omega\n",
    "\\end{array}\n",
    "\\right.\n",
    "$$\n",
    "\n",
    "Let $\\Omega \\in [0, 1]^2$, $u=\\sin(2\\pi x)\\sin(2\\pi y)$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Problem(object):\n",
    "    \"\"\"Description of Poisson equation\"\"\"\n",
    "    def __init__(self, domain=(0, 1, 0, 1)):\n",
    "        self.domain = domain\n",
    "        \n",
    "    def __repr__(self):\n",
    "        return f'{self.__doc__}'\n",
    "    \n",
    "    \n",
    "    def u(self, x, order=0, verbose=None):\n",
    "        temp = np.sin(2*np.pi*x[:, [0]]) * np.sin(2*np.pi*x[:, [1]])\n",
    "        if order == 0:\n",
    "            out = temp\n",
    "        elif order == 1:\n",
    "            u_x = 2*np.pi * np.cos(2*np.pi*x[:, [0]]) * np.sin(2*np.pi*x[:, [1]])\n",
    "            u_y = 2*np.pi * np.sin(2*np.pi*x[:, [0]]) * np.cos(2*np.pi*x[:, [1]])\n",
    "            out = np.hstack((u_x, u_y))\n",
    "        elif order == 2:\n",
    "            u_xx = - (2*np.pi)**2 * temp\n",
    "            u_yy = u_xx\n",
    "            out = np.hstack((u_xx, u_yy))\n",
    "        \n",
    "        if verbose == 'tensor':\n",
    "            return torch.from_numpy(out).float()\n",
    "        return out\n",
    "    \n",
    "    def a(self, x, order=0, verbose=None):\n",
    "        if order == 0:\n",
    "            out = np.ones_like(x[:, [0]])\n",
    "        elif order == 1:\n",
    "            a_x = np.zeros_like(x[:, [0]])\n",
    "            a_y = a_x\n",
    "            out = np.hstack((a_x, a_y))\n",
    "        \n",
    "        if verbose == 'tensor':\n",
    "            return torch.from_numpy(out).float()\n",
    "        return out\n",
    "    \n",
    "    def f(self, x, verbose=None):\n",
    "        a     = self.a(x, order=0, verbose=verbose)\n",
    "        a_1st = self.a(x, order=1, verbose=verbose)\n",
    "\n",
    "        u     = self.u(x, order=0, verbose=verbose)\n",
    "        u_1st = self.u(x, order=1, verbose=verbose)\n",
    "        u_2nd = self.u(x, order=2, verbose=verbose)\n",
    "        \n",
    "        out = - (a * u_2nd[:, [0]] + a_1st[:, [0]] * u_1st[:, [0]] + \n",
    "                 a * u_2nd[:, [1]] + a_1st[:, [1]] * u_1st[:, [1]])\n",
    "        \n",
    "        return out\n",
    "    \n",
    "    def g(self, x, verbose=None):\n",
    "        return self.u(x, verbose=verbose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Description of Poisson equation\n"
     ]
    }
   ],
   "source": [
    "problem = Problem()\n",
    "print(problem)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Trainset(object):\n",
    "    def __init__(self, problem, *args, **kwargs):\n",
    "        self.problem = problem\n",
    "        self.domain = problem.domain\n",
    "        self.args = args\n",
    "        self.method = kwargs['method']\n",
    "        \n",
    "    def __call__(self, plot=False, verbose=None):\n",
    "        if self.method == 'uniform':\n",
    "            n_x, n_y = self.args[0], self.args[1]\n",
    "            x, x_bc = self._uniform_sample(n_x, n_y)\n",
    "        elif self.method == 'lhs':\n",
    "            n, n_bc = self.args[0], self.args[1]\n",
    "            x, x_bc = self._lhs_sample(n, n_bc)\n",
    "        f = self.problem.f(x)\n",
    "        u = self.problem.u(x)\n",
    "        g = self.problem.g(x_bc)\n",
    "        \n",
    "        if plot:\n",
    "            fig = plt.figure()\n",
    "            ax = fig.add_subplot(111)\n",
    "            ax.scatter(x[:, 0], x[:, 1], facecolor='r', s=10)\n",
    "            ax.scatter(x_bc[:, 0], x_bc[:, 1], facecolor='b', s=10)\n",
    "            ax.set_xlim(-0.01, 1.01)\n",
    "            ax.set_ylim(-0.01, 1.01)\n",
    "            ax.set_aspect('equal')\n",
    "            plt.show()\n",
    "            \n",
    "        if verbose is not None:\n",
    "            x = torch.from_numpy(x).float()\n",
    "            x_bc = torch.from_numpy(x_bc).float()\n",
    "            u = torch.from_numpy(u).float()\n",
    "            f = torch.from_numpy(f).float()\n",
    "            g = torch.from_numpy(g).float()\n",
    "            return x, x_bc, u, f, g\n",
    "        return x, x_bc, u, f, g\n",
    "        \n",
    "    def _uniform_sample(self, n_x, n_y):\n",
    "        x_min, x_max, y_min, y_max = self.domain\n",
    "        x = np.linspace(x_min, x_max, n_x)\n",
    "        y = np.linspace(y_min, y_max, n_y)\n",
    "        x, y = np.meshgrid(x, y)\n",
    "        xy = np.hstack((x.reshape(x.size, -1), y.reshape(y.size, -1)))\n",
    "        \n",
    "        mask = (xy[:, 0] - x_min) * (x_max - xy[:, 0]) * (xy[:, 1] - y_min) * (y_max - xy[:, 1]) == 0\n",
    "        x_bc = xy[mask]\n",
    "        x = xy[np.logical_not(mask)]\n",
    "\n",
    "        return x, x_bc\n",
    "        \n",
    "    def _lhs_sample(self, n, n_bc):\n",
    "        x_min, x_max, y_min, y_max = self.domain\n",
    "\n",
    "        lb = np.array([x_min, y_min])\n",
    "        ub = np.array([x_max, y_max])\n",
    "        x = lb + (ub - lb) * lhs(2, n)\n",
    "\n",
    "        lb = np.array([x_min, y_min])\n",
    "        ub = np.array([x_max, y_min])\n",
    "        x_bc = lb + (ub - lb) * lhs(2, n_bc//4)\n",
    "\n",
    "        lb = np.array([x_min, y_max])\n",
    "        ub = np.array([x_max, y_max])\n",
    "        temp = lb + (ub - lb) * lhs(2, n_bc//4)\n",
    "        x_bc = np.vstack((x_bc, temp))\n",
    "\n",
    "        lb = np.array([x_min, y_min])\n",
    "        ub = np.array([x_min, y_max])\n",
    "        temp = lb + (ub - lb) * lhs(2, n_bc//4)\n",
    "        x_bc = np.vstack((x_bc, temp))\n",
    "\n",
    "        lb = np.array([x_max, y_min])\n",
    "        ub = np.array([x_max, y_max])\n",
    "        temp = lb + (ub - lb) * lhs(2, n_bc//4)\n",
    "        x_bc = np.vstack((x_bc, temp))\n",
    "        \n",
    "        return x, x_bc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "problem = Problem()\n",
    "trainset = Trainset(problem, 40, 40, method='uniform')\n",
    "#trainset = Trainset(problem, 1000, 400, method='lhs')\n",
    "\n",
    "x, x_bc, u, f, g = trainset(plot=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Testset(object):\n",
    "    \"\"\"Dataset on a square domain\"\"\"\n",
    "    def __init__(self, problem, *args, **kwargs):\n",
    "        self.problem = problem\n",
    "        self.domain = problem.domain\n",
    "        self.args = args\n",
    "        self.method = kwargs['method']\n",
    "\n",
    "    def __repr__(self):\n",
    "        return f'{self.__doc__}'\n",
    "        \n",
    "    def __call__(self, plot=False, verbose=None):\n",
    "        if self.method == 'uniform':\n",
    "            n_x, n_y = self.args[0], self.args[1]\n",
    "            X, x, y = self._uniform_sample(n_x, n_y)\n",
    "        u = self.problem.u(X)\n",
    "        u = u.reshape(x.shape)\n",
    "        \n",
    "        if plot == True:\n",
    "            fig = plt.figure()\n",
    "            ax = fig.add_subplot(121)\n",
    "            ax.scatter(X[:, 0], X[:, 1], facecolor='r', s=10)\n",
    "            ax.set_xlim(-0.01, 1.01)\n",
    "            ax.set_ylim(-0.01, 1.01)\n",
    "            ax.set_aspect('equal')\n",
    "            \n",
    "            ax = fig.add_subplot(122, projection='3d')\n",
    "            ax.plot_surface(x, y, u, cmap=cm.coolwarm)\n",
    "            plt.show() \n",
    "            \n",
    "        if verbose == 'tensor':\n",
    "            X = torch.from_numpy(X).float()\n",
    "            \n",
    "        return X, x, y, u\n",
    "\n",
    "    \n",
    "    def _uniform_sample(self, n_x, n_y):\n",
    "        x_min, x_max, y_min, y_max = self.domain\n",
    "        x = np.linspace(x_min, x_max, n_x)\n",
    "        y = np.linspace(y_min, y_max, n_y)\n",
    "        x, y = np.meshgrid(x, y)\n",
    "        X = np.hstack((x.reshape(x.size, -1), y.reshape(y.size, -1)))\n",
    "        return X, x, y\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "testset = Testset(problem, 40, 40, method='uniform')\n",
    "X, x, y, u = testset(plot=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Network Archetecture"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Deep Neural Network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def activation(name):\n",
    "    if name in ['tanh', 'Tanh']:\n",
    "        return nn.Tanh()\n",
    "    elif name in ['relu', 'ReLU']:\n",
    "        return nn.ReLU(inplace=True)\n",
    "    elif name in ['leaky_relu', 'LeakyReLU']:\n",
    "        return nn.LeakyReLU(inplace=True)\n",
    "    elif name in ['sigmoid', 'Sigmoid']:\n",
    "        return nn.Sigmoid()\n",
    "    elif name in ['softplus', 'Softplus']:\n",
    "        return nn.Softplus()\n",
    "    else: \n",
    "        raise ValueError(f'unknown activation function: {name}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DNN(nn.Module):\n",
    "    \"\"\"Deep Neural Network\"\"\"\n",
    "    def __init__(self, dim_in, dim_out, dim_hidden, hidden_layers, act_name='tanh', init_name=None):\n",
    "        super().__init__()\n",
    "        model = nn.Sequential()\n",
    "        \n",
    "        model.add_module('fc0', nn.Linear(dim_in, dim_hidden, bias=True))\n",
    "        model.add_module('act0', activation(act_name))\n",
    "        for i in range(1, hidden_layers):\n",
    "            model.add_module(f'fc{i}', nn.Linear(dim_hidden, dim_hidden, bias=True))\n",
    "            model.add_module(f'act{i}', activation(act_name))\n",
    "        model.add_module(f'fc{hidden_layers}', nn.Linear(dim_hidden, dim_out, bias=True))\n",
    "        \n",
    "        self.model = model\n",
    "        if init_name is not None:\n",
    "            self.init_weight(init_name)\n",
    "            \n",
    "    def init_weight(self, name):\n",
    "        if name == 'xavier_normal':\n",
    "            nn_init = nn.init.xavier_normal_\n",
    "        elif name == 'xavier_uniform':\n",
    "            nn_init = nn.init.xavier_uniform_\n",
    "        elif name == 'kaiming_normal':\n",
    "            nn_init = nn.init.kaiming_normal_\n",
    "        elif name == 'kaiming_uniform':\n",
    "            nn_init =  nn.init.kaiming_uniform_\n",
    "        else:\n",
    "            raise ValueError(f'unknown initialization function: {name}')\n",
    "    \n",
    "        for param in self.parameters():\n",
    "            if len(param.shape) > 1:\n",
    "                nn_init(param)\n",
    "                \n",
    "    def forward(self, x):\n",
    "        return self.model(x)\n",
    "    \n",
    "    def forward_test(self, x):\n",
    "        print(f\"{'input':<20}{str(x.shape):<40}\")\n",
    "        for name, module in self.model._modules.items():\n",
    "              x = module(x)\n",
    "              print(f\"{name:<20}{str(x.shape):<40}\")\n",
    "        return x              \n",
    "    \n",
    "    def model_size(self):\n",
    "        n_params = 0\n",
    "        for param in self.parameters():\n",
    "            n_params += param.numel()\n",
    "        return n_params                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "DNN(\n",
      "  (model): Sequential(\n",
      "    (fc0): Linear(in_features=2, out_features=20, bias=True)\n",
      "    (act0): Tanh()\n",
      "    (fc1): Linear(in_features=20, out_features=20, bias=True)\n",
      "    (act1): Tanh()\n",
      "    (fc2): Linear(in_features=20, out_features=20, bias=True)\n",
      "    (act2): Tanh()\n",
      "    (fc3): Linear(in_features=20, out_features=20, bias=True)\n",
      "    (act3): Tanh()\n",
      "    (fc4): Linear(in_features=20, out_features=1, bias=True)\n",
      "  )\n",
      ")\n",
      "1341\n"
     ]
    }
   ],
   "source": [
    "model = DNN(2, 1, 20, 4, init_name='kaiming_normal')\n",
    "print(model)\n",
    "print(model.model_size())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input               torch.Size([5, 2])                      \n",
      "fc0                 torch.Size([5, 20])                     \n",
      "act0                torch.Size([5, 20])                     \n",
      "fc1                 torch.Size([5, 20])                     \n",
      "act1                torch.Size([5, 20])                     \n",
      "fc2                 torch.Size([5, 20])                     \n",
      "act2                torch.Size([5, 20])                     \n",
      "fc3                 torch.Size([5, 20])                     \n",
      "act3                torch.Size([5, 20])                     \n",
      "fc4                 torch.Size([5, 1])                      \n"
     ]
    }
   ],
   "source": [
    "x = torch.randn(5, 2)\n",
    "y = model.forward_test(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Residual DNN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResBlock(nn.Module):\n",
    "    def __init__(self, dim_in, dim_out, dim_hidden, act_name='tanh'):\n",
    "        super().__init__()\n",
    "        \n",
    "        assert(dim_in == dim_out)\n",
    "        \n",
    "        block = nn.Sequential()\n",
    "        block.add_module('act', activation(act_name))\n",
    "        block.add_module('fc0', nn.Linear(dim_in, dim_hidden, bias=True))\n",
    "        block.add_module('fc1', nn.Linear(dim_hidden, dim_out, bias=True))\n",
    "        self.block = block\n",
    "        \n",
    "    def forward(self, x):\n",
    "        res = x\n",
    "        out = self.block(x)\n",
    "        return res + out"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResDNN(nn.Module):\n",
    "    def __init__(self, dim_in, dim_out, dim_hidden, res_blocks, act_name='tanh', init_name='kaiming_normal'):\n",
    "        super().__init__()\n",
    "        \n",
    "        model = nn.Sequential()\n",
    "        model.add_module('fc_first', nn.Linear(dim_in, dim_hidden, bias=True))\n",
    "        for i in range(res_blocks):\n",
    "            res_block = ResBlock(dim_hidden, dim_hidden, dim_hidden, act_name=act_name)\n",
    "            model.add_module(f'res_block{i+1}', res_block)\n",
    "        model.add_module('act_last', activation(act_name))\n",
    "        model.add_module('fc_last', nn.Linear(dim_hidden, dim_out, bias=True))\n",
    "        \n",
    "        self.model = model\n",
    "        if init_name is not None:\n",
    "            self.init_weight(init_name)\n",
    "        \n",
    "    def init_weight(self, name):\n",
    "        if name == 'xavier_normal':\n",
    "            nn_init = nn.init.xavier_normal_\n",
    "        elif name == 'xavier_uniform':\n",
    "            nn_init = nn.init.xavier_uniform_\n",
    "        elif name == 'kaiming_normal':\n",
    "            nn_init = nn.init.kaiming_normal_\n",
    "        elif name == 'kaiming_uniform':\n",
    "            nn_init =  nn.init.kaiming_uniform_\n",
    "        else:\n",
    "            raise ValueError(f'unknown initialization function: {name}')\n",
    "    \n",
    "        for param in self.parameters():\n",
    "            if len(param.shape) > 1:\n",
    "                nn_init(param)\n",
    "\n",
    "    def forward(self, x):\n",
    "        return self.model(x)\n",
    "\n",
    "    def forward_test(self, x):\n",
    "        print(f\"{'input':<20}{str(x.shape):<40}\")\n",
    "        for name, module in self.model._modules.items():\n",
    "              x = module(x)\n",
    "              print(f\"{name:<20}{str(x.shape):<40}\")\n",
    "        return x              \n",
    "    \n",
    "    def model_size(self):\n",
    "        n_params = 0\n",
    "        for param in self.parameters():\n",
    "            n_params += param.numel()\n",
    "        return n_params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ResDNN(\n",
      "  (model): Sequential(\n",
      "    (fc_first): Linear(in_features=2, out_features=10, bias=True)\n",
      "    (res_block1): ResBlock(\n",
      "      (block): Sequential(\n",
      "        (act): Tanh()\n",
      "        (fc0): Linear(in_features=10, out_features=10, bias=True)\n",
      "        (fc1): Linear(in_features=10, out_features=10, bias=True)\n",
      "      )\n",
      "    )\n",
      "    (res_block2): ResBlock(\n",
      "      (block): Sequential(\n",
      "        (act): Tanh()\n",
      "        (fc0): Linear(in_features=10, out_features=10, bias=True)\n",
      "        (fc1): Linear(in_features=10, out_features=10, bias=True)\n",
      "      )\n",
      "    )\n",
      "    (res_block3): ResBlock(\n",
      "      (block): Sequential(\n",
      "        (act): Tanh()\n",
      "        (fc0): Linear(in_features=10, out_features=10, bias=True)\n",
      "        (fc1): Linear(in_features=10, out_features=10, bias=True)\n",
      "      )\n",
      "    )\n",
      "    (res_block4): ResBlock(\n",
      "      (block): Sequential(\n",
      "        (act): Tanh()\n",
      "        (fc0): Linear(in_features=10, out_features=10, bias=True)\n",
      "        (fc1): Linear(in_features=10, out_features=10, bias=True)\n",
      "      )\n",
      "    )\n",
      "    (act_last): Tanh()\n",
      "    (fc_last): Linear(in_features=10, out_features=1, bias=True)\n",
      "  )\n",
      ")\n",
      "921\n"
     ]
    }
   ],
   "source": [
    "model = ResDNN(2, 1, 10, 4, init_name='kaiming_normal')\n",
    "print(model)\n",
    "print(model.model_size())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input               torch.Size([5, 2])                      \n",
      "fc_first            torch.Size([5, 10])                     \n",
      "res_block1          torch.Size([5, 10])                     \n",
      "res_block2          torch.Size([5, 10])                     \n",
      "res_block3          torch.Size([5, 10])                     \n",
      "res_block4          torch.Size([5, 10])                     \n",
      "act_last            torch.Size([5, 10])                     \n",
      "fc_last             torch.Size([5, 1])                      \n"
     ]
    }
   ],
   "source": [
    "x = torch.randn(5, 2)\n",
    "y = model.forward_test(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Physics Informed Neural Networks (PINN)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def grad(outputs, inputs):\n",
    "    return torch.autograd.grad(outputs, inputs,\n",
    "                               grad_outputs=torch.ones_like(outputs),\n",
    "                               create_graph=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PINN(DNN):\n",
    "    \"\"\"Physics Constrained Neural Networks\n",
    "    \"\"\"\n",
    "    def __init__(self, dim_in, dim_out, dim_hidden, hidden_layers, act_name='tanh', init_name='xavier_normal'):\n",
    "        super().__init__(dim_in, dim_out, dim_hidden, hidden_layers, act_name=act_name, init_name=init_name)\n",
    "        \n",
    "    def forward(self, problem, x, x_bc=None):\n",
    "        x.requires_grad_(True)\n",
    "        u = super().forward(x)\n",
    "\n",
    "        grad_u = grad(u, x)[0]        \n",
    "        u_x = grad_u[:, [0]]\n",
    "        u_y = grad_u[:, [1]]\n",
    "        u_xx = grad(u_x, x)[0][:, [0]]\n",
    "        u_yy = grad(u_y, x)[0][:, [1]]\n",
    "\n",
    "        x.detach_()\n",
    "        x_ = x.cpu().numpy()        \n",
    "        a = problem.a(x_, verbose='tensor')\n",
    "        grad_a = problem.a(x_, order=1, verbose='tensor')\n",
    "        a_x = grad_a[:, [0]]\n",
    "        a_y = grad_a[:, [1]]\n",
    "\n",
    "        f = -( a * u_xx + a_x * u_x + a * u_yy + a_y * u_y )\n",
    "        \n",
    "        \n",
    "        if x_bc is not None:\n",
    "            g = super().forward(x_bc)\n",
    "            return u, f, g\n",
    "        return u, f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResPINN(DNN):\n",
    "    \"\"\"Physics Constrained Neural Networks\n",
    "    \"\"\"\n",
    "    def __init__(self, dim_in, dim_out, dim_hidden, res_blocks, act_name='tanh', init_name='xavier_normal'):\n",
    "        super().__init__(dim_in, dim_out, dim_hidden, res_blocks, act_name=act_name, init_name=init_name)\n",
    "        \n",
    "    def forward(self, problem, x, x_bc=None):\n",
    "        x.requires_grad_(True)\n",
    "        u = super().forward(x)\n",
    "\n",
    "        grad_u = grad(u, x)[0]        \n",
    "        u_x = grad_u[:, [0]]\n",
    "        u_y = grad_u[:, [1]]\n",
    "        u_xx = grad(u_x, x)[0][:, [0]]\n",
    "        u_yy = grad(u_y, x)[0][:, [1]]\n",
    "\n",
    "        x.detach_()\n",
    "        x_ = x.cpu().numpy()        \n",
    "        a = problem.a(x_, verbose='tensor')\n",
    "        grad_a = problem.a(x_, order=1, verbose='tensor')\n",
    "        a_x = grad_a[:, [0]]\n",
    "        a_y = grad_a[:, [1]]\n",
    "\n",
    "        f = -( a * u_xx + a_x * u_x + a * u_yy + a_y * u_y )\n",
    "        \n",
    "        if x_bc is not None:\n",
    "            g = super().forward(x_bc)\n",
    "            return u, f, g\n",
    "        return u, f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "problem = Problem()\n",
    "trainset = Trainset(problem, 40, 40, method='uniform')\n",
    "#trainset = Trainset(problem, 1000, 400, method='lhs')\n",
    "\n",
    "x, x_bc, u, f, g = trainset(plot=True, verbose='tensor')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "811\n",
      "torch.Size([1444, 1]) torch.Size([1444, 1]) torch.Size([156, 1])\n"
     ]
    }
   ],
   "source": [
    "model = PINN(2, 1, 10, 8)\n",
    "print(model.model_size())\n",
    "\n",
    "u_pred, f_pred, g_pred = model(problem, x, x_bc)\n",
    "print(u_pred.shape, f_pred.shape, g_pred.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "371\n",
      "torch.Size([1444, 1]) torch.Size([1444, 1]) torch.Size([156, 1])\n"
     ]
    }
   ],
   "source": [
    "model = ResPINN(2, 1, 10, 4)\n",
    "print(model.model_size())\n",
    "\n",
    "u_pred, f_pred, g_pred = model(problem, x, x_bc)\n",
    "print(u_pred.shape, f_pred.shape, g_pred.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "import argparse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Options(object):\n",
    "    def __init__(self):\n",
    "        parser = argparse.ArgumentParser()\n",
    "        parser.add_argument('--no_cuda', action='store_true', default=False, help='disable CUDA or not')\n",
    "        parser.add_argument('--dim_hidden', type=int, default=10, help='neurons in hidden layers')\n",
    "        parser.add_argument('--hidden_layers', type=int, default=4, help='number of hidden layers')\n",
    "        parser.add_argument('--res_blocks', type=int, default=4, help='number of residual blocks')\n",
    "        parser.add_argument('--dropout', type=float, default=0.5, help='dropout rate')\n",
    "        parser.add_argument('--lam', type=float, default=1, help='weight in loss function')\n",
    "        parser.add_argument('--lr', type=float, default=1e-3, help='initial learning rate')\n",
    "        parser.add_argument('--epochs_Adam', type=int, default=1000, help='epochs for Adam optimizer')\n",
    "        parser.add_argument('--epochs_LBFGS', type=int, default=200, help='epochs for LBFGS optimizer')\n",
    "        parser.add_argument('--step_size', type=int, default=2000, help='step size in lr_scheduler for Adam optimizer')\n",
    "        parser.add_argument('--gamma', type=float, default=0.7, help='gamma in lr_scheduler for Adam optimizer')\n",
    "        parser.add_argument('--resume', type=bool, default=False, help='resume or not')\n",
    "        parser.add_argument('--sample_method', type=str, default='lhs', help='sample method')\n",
    "        parser.add_argument('--n_x', type=int, default=100, help='sample points in x-direction for uniform sample')\n",
    "        parser.add_argument('--n_y', type=int, default=100, help='sample points in y-direction for uniform sample')\n",
    "        parser.add_argument('--n', type=int, default=10000, help='sample points in domain for lhs sample')\n",
    "        parser.add_argument('--n_bc', type=int, default=400, help='sample points on the boundary for lhs sample')\n",
    "        parser.add_argument('--case', type=int, default=1, help='problem case')\n",
    "        \n",
    "        self.parser = parser\n",
    "    def parse(self):\n",
    "        arg = self.parser.parse_args(args=[])\n",
    "        arg.cuda = not arg.no_cuda and torch.cuda.is_available()\n",
    "        arg.device = torch.device('cpu')#('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "        return arg\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Namespace(case=1, cuda=True, device=device(type='cpu'), dim_hidden=10, dropout=0.5, epochs_Adam=1000, epochs_LBFGS=200, gamma=0.7, hidden_layers=4, lam=1, lr=0.001, n=10000, n_bc=400, n_x=100, n_y=100, no_cuda=False, res_blocks=4, resume=False, sample_method='lhs', step_size=2000)\n"
     ]
    }
   ],
   "source": [
    "args = Options().parse()\n",
    "print(args)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Training Process"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "def save_model(state, is_best=None, save_dir=None):\n",
    "    last_model = os.path.join(save_dir, 'last_model.pth.tar')\n",
    "    torch.save(state, last_model)\n",
    "    if is_best:\n",
    "        best_model = os.path.join(save_dir, 'best_model.pth.tar')\n",
    "        shutil.copyfile(last_model, best_model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Trainer(object):\n",
    "    def __init__(self, args):\n",
    "        self.device  = args.device\n",
    "        self.problem = args.problem\n",
    "        \n",
    "        self.lam = args.lam\n",
    "        self.criterion = nn.MSELoss()\n",
    "        \n",
    "        self.model = args.model\n",
    "        self.model_name = self.model.__class__.__name__\n",
    "        self.model_path = self._model_path()\n",
    "                \n",
    "        self.epochs_Adam = args.epochs_Adam\n",
    "        self.epochs_LBFGS = args.epochs_LBFGS\n",
    "        self.optimizer_Adam = optim.Adam(self.model.parameters(), lr=args.lr)\n",
    "        self.optimizer_LBFGS = optim.LBFGS(self.model.parameters(), max_iter=20, tolerance_grad=1.e-8, tolerance_change=1.e-12)\n",
    "        self.lr_scheduler = StepLR(self.optimizer_Adam, step_size=args.step_size, gamma=args.gamma)\n",
    "\n",
    "        self.model.to(self.device)\n",
    "        self.model.zero_grad()\n",
    "        \n",
    "        self.x,     self.x_bc,     _, self.f,     self.g     = args.trainset(verbose='tensor')\n",
    "        self.x_val, self.x_bc_val, _, self.f_val, self.g_val = args.validset(verbose='tensor')\n",
    "        \n",
    "        if self.device == torch.device(type='cuda'):\n",
    "            for item in [self.x, self.x_bc, self.f, self.g, self.x_val, self.x_bc_val, self.f_val, self.g_val]:\n",
    "                item = item.to(self.device)\n",
    "        \n",
    "    def _model_path(self):\n",
    "        \"\"\"Path to save the model\"\"\"\n",
    "        if not os.path.exists('checkpoints'):\n",
    "            os.mkdir('checkpoints')\n",
    "\n",
    "        path = os.path.join('checkpoints', self.model_name)\n",
    "        if not os.path.exists(path):\n",
    "            os.mkdir(path)\n",
    "    \n",
    "        return path\n",
    "    \n",
    "    def train(self):\n",
    "        best_loss = 1.e10\n",
    "        \n",
    "        for epoch in range(self.epochs_Adam):\n",
    "            loss, loss1, loss2 = self.train_Adam()\n",
    "            if (epoch + 1) % 100 == 0:\n",
    "                self.infos_Adam(epoch+1, loss, loss1, loss2)\n",
    "                \n",
    "                valid_loss = self.validate(epoch)\n",
    "                is_best = valid_loss < best_loss\n",
    "                best_loss = valid_loss if is_best else best_loss                \n",
    "                state = {\n",
    "                    'epoch': epoch,\n",
    "                    'state_dict': self.model.state_dict(),\n",
    "                    'best_loss': best_loss\n",
    "                }\n",
    "                save_model(state, is_best, save_dir=self.model_path)\n",
    "                \n",
    "            \n",
    "        for epoch in range(self.epochs_Adam, self.epochs_Adam + self.epochs_LBFGS):\n",
    "            loss, loss1, loss2 = self.train_LBFGS()\n",
    "            if (epoch + 1) % 20 == 0:\n",
    "                self.infos_LBFGS(epoch+1, loss, loss1, loss2)\n",
    "                \n",
    "                valid_loss = self.validate(epoch)\n",
    "                is_best = valid_loss < best_loss\n",
    "                best_loss = valid_loss if is_best else best_loss                \n",
    "                state = {\n",
    "                    'epoch': epoch,\n",
    "                    'state_dict': self.model.state_dict(),\n",
    "                    'best_loss': best_loss\n",
    "                }\n",
    "                save_model(state, is_best, save_dir=self.model_path)\n",
    "            \n",
    "    def train_Adam(self):\n",
    "        self.optimizer_Adam.zero_grad()\n",
    "\n",
    "        _, f_pred, g_pred = self.model(self.problem, self.x, self.x_bc)\n",
    "        loss1 = self.criterion(f_pred, self.f)\n",
    "        loss2 = self.criterion(g_pred, self.g)\n",
    "        loss = loss1 + self.lam * loss2\n",
    "\n",
    "        loss.backward()\n",
    "        self.optimizer_Adam.step()\n",
    "        self.lr_scheduler.step()\n",
    "\n",
    "        return loss.item(), loss1.item(), loss2.item()\n",
    "\n",
    "    def infos_Adam(self, epoch, loss, loss1, loss2):\n",
    "        infos = 'Adam  ' + \\\n",
    "            f'Epoch #{epoch:5d}/{self.epochs_Adam+self.epochs_LBFGS} ' + \\\n",
    "            f'Loss: {loss:.4e} = {loss1:.4e} + {self.lam} * {loss2:.4e} ' + \\\n",
    "            f'lr: {self.lr_scheduler.get_lr()[0]:.2e} '\n",
    "        print(infos)\n",
    "        \n",
    "    def train_LBFGS(self):\n",
    "\n",
    "        # only used to compute loss_int and loss_bc1 for monitoring\n",
    "        _, f_pred, g_pred = self.model(self.problem, self.x, self.x_bc)\n",
    "        loss1 = self.criterion(f_pred, self.f)\n",
    "        loss2 = self.criterion(g_pred, self.g)\n",
    "\n",
    "        def closure():\n",
    "            if torch.is_grad_enabled():\n",
    "                self.optimizer_LBFGS.zero_grad()\n",
    "            _, f_pred, g_pred = self.model(self.problem, self.x, self.x_bc)               \n",
    "            loss1 = self.criterion(f_pred, self.f)\n",
    "            loss2 = self.criterion(g_pred, self.g)\n",
    "            loss = loss1 + self.lam * loss2\n",
    "            if loss.requires_grad:\n",
    "                loss.backward()\n",
    "            return loss\n",
    "\n",
    "        self.optimizer_LBFGS.step(closure)\n",
    "        loss = closure()\n",
    "\n",
    "        return loss.item(), loss1.item(), loss2.item()\n",
    "        \n",
    "    def infos_LBFGS(self, epoch, loss, loss1, loss2):\n",
    "        infos = 'LBFGS ' + \\\n",
    "            f'Epoch #{epoch:5d}/{self.epochs_Adam+self.epochs_LBFGS} ' + \\\n",
    "            f'Loss: {loss:.2e} = {loss1:.2e} + {self.lam:d} * {loss2:.2e} '\n",
    "        print(infos)\n",
    "\n",
    "    def validate(self, epoch):\n",
    "        self.model.eval()\n",
    "        _, f_pred, g_pred = self.model(self.problem, self.x_val, self.x_bc_val)\n",
    "        loss1 = self.criterion(f_pred, self.f_val)\n",
    "        loss2 = self.criterion(g_pred, self.g_val)\n",
    "        loss = loss1 + self.lam * loss2\n",
    "        \n",
    "        infos = 'Valid ' + \\\n",
    "            f'Epoch #{epoch+1:5d}/{self.epochs_Adam+self.epochs_LBFGS} ' + \\\n",
    "            f'Loss: {loss:.4e} '\n",
    "        print(infos)\n",
    "        self.model.train()\n",
    "        return loss.item()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "d:\\program files (x86)\\python\\lib\\site-packages\\torch\\optim\\lr_scheduler.py:351: UserWarning: To get the last learning rate computed by the scheduler, please use `get_last_lr()`.\n",
      "  \"please use `get_last_lr()`.\", UserWarning)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adam  Epoch #  100/1200 Loss: 1.0112e+03 = 1.0090e+03 + 1 * 2.1233e+00 lr: 1.00e-03 \n",
      "Valid Epoch #  100/1200 Loss: 1.0228e+03 \n",
      "Adam  Epoch #  200/1200 Loss: 7.8120e+02 = 7.7994e+02 + 1 * 1.2628e+00 lr: 1.00e-03 \n",
      "Valid Epoch #  200/1200 Loss: 7.8454e+02 \n",
      "Adam  Epoch #  300/1200 Loss: 6.9282e+02 = 6.9208e+02 + 1 * 7.4079e-01 lr: 1.00e-03 \n",
      "Valid Epoch #  300/1200 Loss: 6.9761e+02 \n",
      "Adam  Epoch #  400/1200 Loss: 3.9930e+02 = 3.9827e+02 + 1 * 1.0290e+00 lr: 1.00e-03 \n",
      "Valid Epoch #  400/1200 Loss: 4.0031e+02 \n",
      "Adam  Epoch #  500/1200 Loss: 1.3553e+02 = 1.3385e+02 + 1 * 1.6734e+00 lr: 1.00e-03 \n",
      "Valid Epoch #  500/1200 Loss: 1.2861e+02 \n",
      "Adam  Epoch #  600/1200 Loss: 5.9201e+01 = 5.7857e+01 + 1 * 1.3436e+00 lr: 1.00e-03 \n",
      "Valid Epoch #  600/1200 Loss: 5.4779e+01 \n",
      "Adam  Epoch #  700/1200 Loss: 4.1776e+01 = 4.0504e+01 + 1 * 1.2714e+00 lr: 1.00e-03 \n",
      "Valid Epoch #  700/1200 Loss: 3.8409e+01 \n",
      "Adam  Epoch #  800/1200 Loss: 3.3064e+01 = 3.1916e+01 + 1 * 1.1479e+00 lr: 1.00e-03 \n",
      "Valid Epoch #  800/1200 Loss: 3.0161e+01 \n",
      "Adam  Epoch #  900/1200 Loss: 2.5360e+01 = 2.4403e+01 + 1 * 9.5646e-01 lr: 1.00e-03 \n",
      "Valid Epoch #  900/1200 Loss: 2.2906e+01 \n",
      "Adam  Epoch # 1000/1200 Loss: 1.8225e+01 = 1.7440e+01 + 1 * 7.8541e-01 lr: 1.00e-03 \n",
      "Valid Epoch # 1000/1200 Loss: 1.6273e+01 \n",
      "LBFGS Epoch # 1020/1200 Loss: 1.39e-01 = 1.05e-01 + 1 * 4.50e-02 \n",
      "Valid Epoch # 1020/1200 Loss: 1.2424e-01 \n",
      "LBFGS Epoch # 1040/1200 Loss: 5.04e-02 = 3.51e-02 + 1 * 1.59e-02 \n",
      "Valid Epoch # 1040/1200 Loss: 4.5711e-02 \n",
      "LBFGS Epoch # 1060/1200 Loss: 2.91e-02 = 1.81e-02 + 1 * 1.15e-02 \n",
      "Valid Epoch # 1060/1200 Loss: 2.6954e-02 \n",
      "LBFGS Epoch # 1080/1200 Loss: 1.98e-02 = 1.13e-02 + 1 * 8.68e-03 \n",
      "Valid Epoch # 1080/1200 Loss: 1.8457e-02 \n",
      "LBFGS Epoch # 1100/1200 Loss: 1.54e-02 = 7.04e-03 + 1 * 8.54e-03 \n",
      "Valid Epoch # 1100/1200 Loss: 1.4276e-02 \n",
      "LBFGS Epoch # 1120/1200 Loss: 1.28e-02 = 5.11e-03 + 1 * 7.96e-03 \n",
      "Valid Epoch # 1120/1200 Loss: 1.1944e-02 \n",
      "LBFGS Epoch # 1140/1200 Loss: 1.03e-02 = 3.81e-03 + 1 * 6.57e-03 \n",
      "Valid Epoch # 1140/1200 Loss: 9.6948e-03 \n",
      "LBFGS Epoch # 1160/1200 Loss: 8.32e-03 = 3.38e-03 + 1 * 5.00e-03 \n",
      "Valid Epoch # 1160/1200 Loss: 7.8403e-03 \n",
      "LBFGS Epoch # 1180/1200 Loss: 7.36e-03 = 2.61e-03 + 1 * 4.78e-03 \n",
      "Valid Epoch # 1180/1200 Loss: 7.0221e-03 \n",
      "LBFGS Epoch # 1200/1200 Loss: 6.49e-03 = 2.39e-03 + 1 * 4.13e-03 \n",
      "Valid Epoch # 1200/1200 Loss: 6.2401e-03 \n"
     ]
    }
   ],
   "source": [
    "args = Options().parse()\n",
    "args.problem = Problem()\n",
    "#args.model = PINN(dim_in=2,\n",
    "#                  dim_out=1,\n",
    "#                  dim_hidden=args.dim_hidden,\n",
    " #                 hidden_layers=args.hidden_layers,\n",
    " #                 act_name='sin',\n",
    " #                 dropout=args.dropout)\n",
    "\n",
    "args.model = PINN(2, 1, dim_hidden=args.dim_hidden, hidden_layers=args.hidden_layers)\n",
    "if args.sample_method == 'uniform':\n",
    "    args.trainset = Trainset(args.problem, args.n_x, args.n_y, method='uniform')\n",
    "elif args.sample_method == 'lhs':\n",
    "    args.trainset = Trainset(args.problem, args.n, args.n_bc, method='lhs')\n",
    "\n",
    "args.validset = Trainset(args.problem, 100, 100, method='uniform')\n",
    "    \n",
    "trainer = Trainer(args)\n",
    "trainer.train()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Test Process "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Tester(object):\n",
    "    def __init__(self, args):\n",
    "        self.device  = args.device\n",
    "        self.problem = args.problem\n",
    "        self.criterion = nn.MSELoss()\n",
    "        self.model = args.model\n",
    "        model_name = self.model.__class__.__name__\n",
    "        model_path = os.path.join('checkpoints',\n",
    "                                  model_name,\n",
    "                                  'best_model.pth.tar')\n",
    "        best_model = torch.load(model_path)\n",
    "        self.model.load_state_dict(best_model['state_dict'])        \n",
    "        self.model.to(self.device)\n",
    "        self.X, self.x, self.y, self.u = args.testset(verbose='tensor')\n",
    "        if self.device == torch.device(type='cuda'):\n",
    "            self.X = self.X.to(self.device)\n",
    "    \n",
    "    def predict(self):\n",
    "        self.model.eval()\n",
    "        u_pred, _ = self.model(self.problem, self.X)\n",
    "        u_pred = u_pred.detach().cpu().numpy()\n",
    "        u_pred = u_pred.reshape(self.x.shape)\n",
    "        \n",
    "        fig = plt.figure()\n",
    "        ax = fig.add_subplot(131, projection='3d')\n",
    "        ax.plot_surface(self.x, self.y, self.u, cmap=cm.coolwarm)\n",
    "        ax = fig.add_subplot(132, projection='3d')\n",
    "        ax.plot_surface(self.x, self.y, u_pred, cmap=cm.coolwarm)\n",
    "        ax = fig.add_subplot(133, projection='3d')\n",
    "        ax.plot_surface(self.x, self.y, np.abs(u_pred-self.u), cmap=cm.coolwarm)\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAV0AAADnCAYAAAC9roUQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOy9a4xdWXbf91t77/O499abr242m91Nspv9GPaDnIkUGBCMGJmRxvAkFmxr/EUfEsixrUiIAAkOIEVAgiRQLANGFI3sjAHJmiQYKZLimdhST2LZiCWPNDMastndnG6+ySaLjyJZrMd933PO3vmwz7m8VbxVrCreKlax7x+ieqrqvO5dZ6+9Hv+1ljjnGGKIIYYYYmugnvQDDDHEEEN8mjBUukMMMcQQW4ih0h1iiCGG2EIMle4QQwwxxBZiqHSHGGKIIbYQ5hF/H1Ibtg9kgNcaynX7YJByhaFstwtWlOvQ0h1iiCGG2EIMle4QQwwxxBZiqHSHGGKIIbYQQ6U7xBBDDLGFGCrdIYYYYogtxFDpDjHEEENsIYZKd4ghhhhiCzFUukMMMcQQW4ih0h1iiCGG2EIMle4QQwwxxBZiqHSHGGKIIbYQQ6U7xBBDDLGFGCrdIYYYYogtxI5Wup1Oh3q9TpZlT/pRhhggkiShWq2SpumTfpQhBghrLbVajSRJ+DTPZnxUa8dtC2stSZLQbrdJkoQoioiiCKV29D7yqYdzjjRNybKMarVKFEXEcTyU6w6Hc44kSUjTlCRJCIKAUqmE1vpJP9qWY0e+yYUAAbTWKKW4cuUK169fp91uf6p30Z2ONE1xzqGUQmvN7du3OX/+PK1WayjXHYwsy8iyrCvXarXKBx98QKPRwFr7pB9vS7EjlW6tVmN6ehoR3ydYREiShCzLaDabVKtVOp3OcJHuMKRpyoULF5bItfBoWq0Wi4uLw011B8I5x7lz57reSiHfdrtNp9NhcXHxU7Wp7jil65yj0WgwNze35PeFILXW3WPq9fowLrhDUHgvd+7cWfL7XrmKSHdT/bTHBXcKnHN0Oh1mZmb6/r3wVD9Nm+qOU7pJknQX4kpQSqGUIk1TarUa9Xr9U+fC7DSkabpERv0Wnoh0N9V6vT5Mou4AZFmGtfahNdv7cyFX4FOxqe4opVvEhUTkkQIpBKmUIkkSFhcXaTabQ+W7DWGtJU3TR26mBXo31cXFxU9lXHAnoEiKFnItPNCVUMR7nXNdY+lp3FR3DHuhcD9FZEnM71HotY6KGFIcx4RhuOZFPsTmoTcpqpTqbqaPkk2vXDudTleuURQN5bpN0JsUBbh58yYXL16kUm3x3NufWfE8pRQiQpqmVKtVwjB8qhgsO+ZTFAJcbUGtZv0Wi3QYF9xeWMn97MVa5Pppiwtudyz3XpxzXL16lc997nOE3/6A8//XH63Kxe6V69OWbNsRSne5APuFF9Zq3fSLCw6TbU8Gve7nSh7MeuU63FSfPHq9l0J+rVaLQ4cOYYwhDgOexaC15tSpU9y4cWPF8NDTuKlue6XbT4CDQG9csFqtDuOCTwBr8V7Wi95N9WmOC25nLPde5ufnsdbyzDPP+AOsI525S6lU4vjx47TbbU6ePMns7OyK1+xNtjUaDWq1Wvf92WnY9kp3JfdzEF92IUit9RIXZqh8Nx/rTZ6tF0VSZphs21osz71Ya/n444+J4/hBqMFaknv3ATDGcOjQIY4dO8bt27c5ffo0tVptxesrpTDGYK2lWq3uyE11Wyvd5e5ngUEv1OUuTLVa3fEuzHZGv6ToZmClTXUo181BP6/02rVr7N69e2m5r3NkcwtLzo3jmDfeeINDhw5x/vx5zp49S6fTWfFevZvqTvNUt7XSXa/7+biLaXlc8OrVq8O44CZgLcmzXgxKrsWmeuXKlaHy3QRYa7uUTvBx3Js3b3Lo0KFlBzqy+YW+3//Y2BjvvPMOU1NTnD59mqtXr65oyfbKtd1uc/36darV6raX67ZVuqu5n4+TSFsLCmFevnx5mGwbMHqt3LVgM+R69erVYbJtwOjnvXz88ce8/PLLDzW1cdZikwQ3v9j3WiLC3r17+exnP4tSipMnTzIzM7OinEQEYwy3b99mYWFh2yfbtqXS3Sr381EQkWGybYAoOLUw+BDRejFMtg0Wy73Su3fvIiLs2bOne0xXCVoHDtxiddVrKqU4ePAgb7/9NvPz85w6dYqFhYUVj3fO7Yhk27YsjihKQtdLht6ML3dIwh8c1htW2Ez00tSKZNuwjeTGsNwrzbKMCxcucPz48b7HO2cRAdVurun6YRhy9OhR6vU6Fy9eRGvN4cOHKZVKDx1bGEpFEq9arW67NpLb7u1aS1Z7s8MLK93zaeMLbiVWSoqu9dzNwjDZ9njolzy7fPky+/fvJ47j7nFLZG4tzlqktTalW6BSqfDWW2+xf/9+zpw5w6VLl1YtrtiuybZtpXQ3i5M7SAxJ+BvDRjm5W/UeDDfVjWG591Kr1bh37x4HDx586Njiu3TO/z/Vqm/onlNTU3z2s5+lVCotKa7o935tx8q2bRVeWKv7uZaGN5uNQpjFCJLt5sJsJ2w2J3eQ6JVro9Gg3W5TKpUwxuyI599KLM+9OOf4+OOPee2111YP0ViLwyGN9Vm6vRAR9u/fz969e/nkk084efLkqvfsDRM2m82uXIMg2HK5bhtL93HczyeJIQl/dWzUe3nSm2pBwh8m21bGcrneunWLcrnMxMTEQ8f2GkrOWsQ5pL1yx7G1whjD4cOHOXbsGK1Wi7Nnz65aXFEwHQDq9foTSbZtG6U7iJLQQX5x67nWMC64MjaaPNsuG+92jQs+aSzn5CZJwpUrV3jllVfWcLIDu/ZE2loQxzFjY2McOHCA8+fPc+7cuTUVVzyJyrZtoXTX634+iUTaWjCMCy7FoKh/T/r7W07C/7RvqgWTp1euFy5c4MUXXyQIgr7n9MrfWesZDM3BKd0Co6OjvPPOO0xOTnL69Gk++eSTVYsrnsSm+sSVrnOuGwjfDoqzwONY3cNkm//+ZmZmaLVajyXX7fROFK6pUopms/mp3VTn5uZYXFzsymZhYYF6vc7+/ftXPW8JTxfWzV54FIo1WxRXnDhxAmBNxRVbmWx74ko3y7JVd6N+2A6JtLXg09zxylrL7du3aW6CNfOk0RsX3M4k/M2AtZbZ2Vnm5+cBliTP1r5BOrAONYCY7mrQWvPCCy+subiiV/kWm+pmDLh9ouyFXvdzO76wg7KyejvhX716lcnJSSYmJp5aEv56S313KnpJ+Ddv3iQMQ/bs2fPUMlj6rddr164xNTXFyMjIqucuT6Q5LGrAG/JK3uny4oqis1m/4oriWYtOZvfu3SNNU/bv39/1Xh8XT0zpbkZJ6JNKpK0FxS46OztLGIYopciyjDiOqVQqA73Xk0ZvUnQ7bqaDROHOVqtV36C7pyCgXxZ/J6M3Keqco9VqMT09zQ//8A+v+RoiAtYhFiRpeSbDFhkfRXHF7OwsZ86cYWpqihdeeKHrtSxHEcOfn59nbGys+3NvafNG8MRMrV4BrndxFsd3Oh2q1Wr3dzsBzrluXPC3f/u3+drXvvakH2mg6E2KDkrp7gTFXdT9K6X49re/zS/90i896UcaKHopncUsu7Nnz/LKK6+sybJfkkjz1RH+d0l7oM+4Fj2wa9cuTpw4QRzHj5xcAQ8GHty9e5ef+ImfeOznfCKWbr8xLRtZWGfPnqVer1OpVCiXy4RhONBn3AxF3hvsT9N0xWzvTsRyTu4glO5O2kyLz5xl2VMlV3h4yGS9Xsc5ty6rr/iO9vzIZ5h1NchuQLsJUX83fzOhlOK5555j37593eKKQ4cOsWvXrr7PPEi5PhFLdzkndyOWbqfTwVrL8ePH2bNnDzdu3GB2dnbbcyh7P3eSJCu6NjsR26mhzVbjaZZrvyGTd+/e5dVXX93Q9cYPTTHxxkFQCjqtgT3nRgylorjiM5/5DLdv3+b999+nXn9QnrwZct1ypbsSJ3c9StdaS7PZ5OjRo37n3LOH559/HoDvf//73Lt377Gfc7MtXeCpsnT7cXI/DTHdAssX59Ms17t37zI6OrpiIqofet+FeDSksmcEpxS0B6d0HwelUok33niDF198kbNnz3aLKzZjvW6p0l2pJHS9ym16errb66A4VynF1NQUb731FjMzMw/tWNsFT6vSXUmun0al+zSFF4o2q8Vnq9frLC4uMj4+/hhXdZSnAhAZqKU7CIyPj3P8+HEmJiY4ffo0d+/e7b7DO1LpruR+rmdxttttbt26RRRFD10DIIqi7o718ccfc/HixQ1PfdgKS/dpoBctLwkt8GlLpD1t4YV+YYWPP/6YAwcOrPtaS94N5wjiEBdFTzy80A8iwr59+7rFFTdu3OD3fu/3+PEf/3G+9a1v8Su/8it97/2zP/uzHDlyhDfffBMROd5zvd8UkTsicga2UOmuVhK6nsV5/vx5Dh069Mgvd3x8nBMnTlAulzl16hQ3b95c1+LdrIW+fHEOMvn3JNCvJLTApzGRBk9HeKGfV3r79m3iOGZ0dHRDcn1wTv7f0bFtZ+n2QmvN5OQkzzzzDL/8y7/Mj/3Yj/FX/spf4etf/zofffTRkmPfffddLly4wIULF/jqV78K8E96/vzPgR8tftgSpfuoTlNrXZxzc3O022327t27puNFfPu348ePU6/XH1mR0u98gKzT4c7//a9J649fQbPc0t3pFtFqjYp2Qnhh9l//KZ3Zuce+Tm9mP8uyHS/X5V5pmqZcvny529DmseSan6pGKtvS0l1+zbNnz3L06FE+97nPcerUKY4dO8Y3v/nNJcd985vf5Cd/8icRkYK3PCEiz+bX+BPgfnHslrwZK7mfBdayOIsPn5vu67q/MYaXX365W5ESBAGHDx9+KESx/H4AaavFmf/079C8fptr47/Bm//yNwl3Ta7r/suv+7TEdNfSqGg7K92P/rOfZ+G77wPCG7/zPzN27LUNX+tpsnT7tVm9cOECL7zwAmEYbkixLT3HvxNqpILrtNnOvoxzjjt37nDgwAEOHjzIj/7oj/KX/tJf4i/+4i+WHHfjxo1uMj/HNPAccGv5NTfd0l1Lp6m1KN3r168zNTW1avXWo65RqVR488032bt3L++//z5Xr159JMXs0j/472lemyadnSerVrn48//tqsc/Cr3Ww05enGvpk7udQwM3vvo1qt9/H1troI3jyj/4Hx7rek+LXOFh72VhYYFqtcpzzz0HbNyDcc758/JzTTkeuKU7aPRes9PpEARBt/x7Dffu+8tNV7qD6JPb6XS4fv06hw8fBh6vtaOIsHv3bj772c8iIl2KWb8vzd2fo/HBB4hLCaZissUa9Y8+pnbp0oY/y9MSXlgLJ3dQMd2BL6Ys4+43/iW21UCXNOlijc6dGe79q3c3fMmnxYNZKXnW29BmIzJZnkhDBF2KoDO4irSH7jMAOOd49tlnmZ6e7rJSpqenH+qoduDAAa5fv77kV8DNftfcVKW71j65jxLihQsXOHTo0EAVlFKKF154gbfeeos7d+7wwQcfPESK5g//kKzeRMcBplIi2jeOjhS3vvK/Pta9d/ri7Od+9sN2jenKv/8zsvvz6HKMMopo3zjBaMjd//MPNnzNpyG80M8rvX79OpOTk4yOjnaPexxLt7exeBgPXukOGs453nzzTS5fvsz09DQiwu/8zu/wpS99aclxX/rSl/ja176Gc47vfOc7AAvOuYdCC7CJMd21uJ8FVhNi0avz9ddfX3L8oBBFEa+//joLCwucPXuWsbExXnrpJe8Knb9EMKZBQrJGhijAZrQuXn0s632nL87lJaErQUS2ZYWgOnkSXdGYkQCXCFm9SVaztG/O0L51i+jZZ9d9zafB0l3uvbTbba5fv84P/dAPLTluo0q3Xq/z4Ycf8jlqlJ0jLIfQ2v6JtCAI+NVf/VV+5md+hlarxc///M/zxhtv8E//6T8F4O/+3b/LF7/4Rf7oj/6II0eOUC6XAf5+cQ0R+Trwl4HdIjK9aUp3PSWhKwmxSJ69/vrrmx4fLEjRt2/f5tSpU0zeu4t2HUBhk5SgrHDWkbUdyjWZ/9f/L5Of/8K679P7OXdieGE9Uz62o6WbzM9jmlUkDHBJikgbF4EEESaC+//iD3j27/+X677uTg8b9bNyz507x8svv/zQZ9moXC9fvsxbb71F9PG/o9NYQEy4IyxdEeELX/gC/+gf/SPOnTvHL/7iLwJe2RYQEb7yla/0nvr9nmv87d4/bEp4Ya3u5/JzluPmzZuMjY0tcW1WO28Q8cNnn32W48ePk/y7fwtpRtZJyBot0noTISUYCxElVP/9nzzWvWDnWURrSYr2Yjsq3blv/gGSZH4ibZoCQjAaYULQgaJx5sMNXXcnK91+Xuns7CxpmrJ3796B3KPdbhNFEaOjo5gg8MwhY2g2m8zOzg7kHrA5Md1Be6abonSL0TTrSW71u8bVq1c5cuTIhq+xURhjCGdnCUqGcMxQmgpxaYYpBRjtv7TO0qD5mtH7nDutOGJ5SehWYNCKu/WDM6hQEcZCGAs2zQjKISoMcEmH9P590lWmya6EnVz0spzSaa3l3LlzvPZafwrdemWSZRm1Wo0XX3zR/8I5EIUEAXG5zO3bt/nggw+25ZSRHdHw5lGc3H7oJ8SLFy+u2mC499xBo/nJVSRtIYAJDCqOiHaPkHUybJZikw5aEtrTnzzWfXaSRbTe4aHw6MW51VawzTLS+/cwRmHTDCcQTY2QVBsoLeBAB1D/s/V7MTvV0u3nvVy5coVnnnlm1ckK65HdlStXKJfLS78TwSveyDeaef755zlz5gyXL1/eViOtlvfU2HZKd7WS0NWwXIjVapXFxUUa/+x3+JNX/yO++yN/g/adx+8ctlY0//z/Q4lDlCBYTBQQjZf9XKcoIJgaRbDU/uTfPNZ9dkoibT1J0V6stDhv/O//gj/5zH/Mt9/8Agvf/2Bgz/koNL//5yhSL0clmFKMiZX3YkZiol3jGCO0f/Deuq+9vHprJ8gVHqZ0NhoN7ty588Aq7YP1KN1ms8mdO3eK5FLvVfy/uARZyuTkJCdOnCAIAk6ePLmk0cyTRG/CeFuGF6rVKufOnVu39dkrxCJ59tx8lVv/xzewc1Ualz/hB//FL/Q9rxeDElJy+QJYi1KCCgJEa3QcEO0aJRotY7QfaNo69/Fj3WenLM4syzh9+vRjybVA8/oNrvxPXyGduU9Wr3L2v/pvHjrmUT9vFI3TfwHWgsuQ0KCiAGU08Z5xtBG0EcQY2tfW78FsxuLcbFhrOXXq1EOc3KNHjz6SmbJWmZw7d45Xn392WUGB5+k6gCgG6y1bpRTPP/88b7/9Nvfu3dsWnQI3o+hlYErXWkuSJDQa6+9P0Ls4Z2ZmKJVK3P7H/wytLXokIKjEtD65yr0/XtmyHGSYIbt/F9GKaGqEeNcYyvhxHeFojLMWHRi0gvad25w/f75rBa4XO0HpFknRRqMxEKV74Zf/R0ibmJEQAdJ6lU/+8a+veo1BIbs1jQDxrjHivePoyKCjkLASYpstRIFYC80myez6PKudFl4ovJdepTYzM0MYhkxNTa167lplcv/+fSTtMHn/k+49RSSv0xL/f2EE2dIugGEY8tprr/HSSy89dqfAx8VmUAEHonQLAW50um2xONM05dKlS+yr1bCLc+g4JJyqoEKBdsL0P/mtQTzuqmhfvQRph3C0jGQZ2JRgtITLUpQSXJri2m2UCJXRiJG5u7z33nvcuHFj3RbZTrCIBjlaPJmfp331CjoKCcZCEIdkCXf/8I833ZXMkgTqVYKxCqJAK0VYiRCbgs2wSYJLfNPqcDSmdfLP1nX9ncbTLSidxbyzYu0dPXr0keeutVfKuXPnOPrs7j6lvpJbugJBCLa/Qi06BZZKJU6dOsXt27e3POSwrdkLhXv1OGT4y5cv8/zzzzP3+3+A63SwSYZrd1CBQ5cM6cIs9YsXB/XIfdH54HvoKESwOOewaYZ0WggO0UIwVkaXI3SlhBIYn53m+PHjNJtNTp48yfz8/Jrvtd0Xp3PusdgKyxfnra/9b9hGC1EKMZqwAiIOOg3ufOMbfc8ZFNof/AVKHAoLDr+JYlEKVBwR7x4nHKsQjFXAZbjrGy/13gmb6fKhsBcvXuTgwYNrYl2stVfKrl27iGwHbIoUfReAIrwAeKWbrWzFigjPPfcc77zzDgsLC7z33nvUNsAu2Si2raUrIt1JqBtZMCJCq9VidnaW559/nsaFi+iKEO4ypPUGZjREjEIrx93f+91BPPKKSK9fQgngHM6B6yRk7TbBSAmSDmFsMHGECRQuc6TT1zDGcOTIEV5//XWuXbvGmTNnaK2h0ibLsg17B1uBQq6DUrqLJ08SVBSmnOCaDYKpMW/0BI75P/7jQT12X6QXP0IZ7TtaKQVpiuu0CcZGUOII4gClQBuFEsHOrT9xu5PCC4VclVIsLCywsLCw5ubkj1K6SZJw/fp1Dh06BG0fbgxcj2ItXicRCIJuTHc1BEHA0aNHefnllzl//vxjhfXWg80IGw10xT+O0r116xavvvoqC9/9MyRt+7hPllE+MEa6WMfEgu20aX70gxWvMxALqbaIOIdogxktIWGAALZZhyxDaUEEdGgQo3Fzd7qnlstl3nzzTZ599lk+/PBDrly5soT+0q9Jz3ZWuo+L3sXZvj+Lm58FB1krJdpbwXbaxHtH0eLo3JgmbTb7KvhByNXduektKq3Q5RiUxmYWlyaIViijcWmKNgJaY2sLZKtYYKthu3swy3Hu3Ll1VX2upVfKSy+95BVUrlCXKF3Hg0SaCZB1fM+jo6O88847jI2N8d577617OMF6se2V7kZr7Wu1GkopJicnqf7bf9NVbsoIYhQq0OhKiAoMWb1G4+L5vvd+XKQL80iWIGGICSHUjvJECT1SQSnlrSKtAdt9mVyzRdpcmjzctWsXJ06cQGvNyZMnuXPnTretXe9zbgdKzGaid3HOv/uHuMzznFVgSJstL9dAoYIAsMy/+6+Apd/LwBJp7QYSBITliEhlRCPGK952h6BcQozBWQdJO0/2WJJz76/58r3PvJOKIzqdziOrPpdjNaVbrVapVqs8W/SvyNeJdtmyc3LKmNErxnRXu/8zzzyzZDjB4uLiuq6xVmxG0cvAle56FUmWZdy9e5d9+/YB0Lp6CQk00UQZU44xpZDS3gm0Vv7nUDH///wh4DmFV65cGVhmMzv3HgpHEHq2gjIGFSiiiVFUHKGjAJcmqHIZl2bo0BCMxGRnTz90LaUUBw8e5O2332Z2dpbTp09Tq9W2tJrrSaP3fWh8eBqwlCZKRFMjBCMlgnIAWeLXXijU3/ONodM05fz58wOrUOrMTKPShKAUAg6XZQhQ2jsFzgJeMYS7JxFjQCAcqWA/ubCh++2E8AJ4hdtqtTh48OBArlfQPV999dUH73naAefQblkIoSAxKLOm8EI/FMMJXn31VS5dukSr1VrSxWwQ2BGW7nqV7tWrV5mYmEBrTbI4T9asE45EaKOIpnymWYwiXaxhQh/4b186B3i3KMuy7k73uJaju3UN0QpfmqQgMKiohA4NulQCl+KSBGOct9Ji34fB3by84jUL+svhw4e5cOECzWZzQ4UGOx3p7F3C0RIq0ISVABMKNsvImk2CSoCIkN6+geATqiLCmTNnBuI+uos/ALF4AzYDo1FxjIglGB/DNRtgE4JQo+PIx+9xyL2+nfn6Ynl5904IL5w7d45KpbLu4agrrfOC7rlkUnDSAmeXWrrOUVi6TqlVE2lrQaVS4e2330ZrzenTp5menh5Yd7uC4QHbLJFWYL1KpNlsMjMzw65du3DOUfuzf4cJNApwWQZZhgkUyiWoQCN4Ynu2sEBaryMiHDlyhLfffptqtcqtW7c2xBMu4BZm/Recx3SVCOThjWB8BBWEmLERdBihSzHaKMgymLv7yGuPjY1x7NgxjDG89957XL169aEX91vf+hZHjx7lyJEjfSeOishfFpEFETmd//vlDX/YLUCxOFufXEGyNmItYjTKKEykMaEmHCuhlM+pZK026upF5ufnOXLkSHca6+zsLPfv33/E3VaGuzuNaA3W+qVuDBIE6DAgnBxHtCYYG/G/1xpjxCuGRnVD99sJMd3Z2Vk6nQ5xHK97U+undLMs49KlS7z88stLD+60PFlhuTUrnqfrZP3hhZWeKQgCTpw4QafT4dSpU+tiEq2EbU0Z2wiKgW/FTtL8+EPIMq9wHdhWi2AkQpTy4YZAI0qjAkV49gNeeeUVz6sMQw4cOMDk5CQfffTRxuu3G4v+RXCgjAYlCAqUQhuNCgPM6IhXHFrR5Xk31k5hieOY48ePc/LkSW7dusWf/umfAv6l/emf/mneffddPvroo74TR3P8qXPu7fzff7f+D7lxbHRx1v7i217ZFRSlTptgfNRblZWST14BphxiLpzhyJEj3STj/v37mZiY4MaNG5w5c4Z2ewOtAOdmUcbgrEVMgAQBYjSiNUosKo7RYYjofDKCNohSkHR8AnUNWN6yc7srXeccr732GlrrgSjdq1evsn///iVzB52z+BXiUK6f5SlYyQ2XAUFrzaFDh7pMoh/84Acbe2dybPvwwnpw7949RIRdu3Z1hWjv3wHnMOUIHYfYTkJaraFCg66UwWhMOUYry+j8DOVyeYl1XSi0on773r21037svZsoZxGlCCbGCMdHCCbH8fwxQBwqDFHa041UGHi+qda4ThtbffSuWgjQGMOP//iPMzU1xa1b3oX93ve+x5EjRzh06BBhGPLlL3/5oYmjTxIbCR0V5yRXLkBm0aUAHfj+xC5NMOXQu5fWoaIQrRyV6jwTExOAb1BT0NaOHTvGs88+y/vvv8+1a9fW7j46hySeFaFHRogmR32MPjCIMSitCMdGIE1wraaP6Trrvd8sw13pu/Gtip0QXtizZ093/azXFV/+LrRaLWZmZnjhhReWHpgmOOWVlLK9ibS8DHiAlu5yFEyiffv2rf+d6cG25emuF9Zazp8/361+ERFcu4VdXCQcqyCSoSUlnBzDpRnhxAg61GSNJto4rINS7YGS6w2eF/Xbb3uRfXoAACAASURBVL31FjMzM2tuGeeunvXUoTBAR/6LFecIR0qQJihnUXEAIthWK1+cDgkDgkoJd/XRfRh640Pgp1b8xE/8BPDwNNEDBw5w48aNfpf5D0XkfRF5V0TeeORNHxPFC/c4SjebvYOpxJhQozUEE2O4JCUoR5gowKYpYWywzhF2mrh8cdRqNTrtVvcZClZIlmVrLkSxt676zVEpTOj7aKA0YSXypH1xqFL0IJxViX3fDaMxYyMws7YWnr2b/05JpMHG5dqLotn5Q/THLAVtQATptXS7txOs0v2nNw4Iu3fv5sSJE1hrOXny5LrDVNs6vLCeeO4nn3zCvn37uq3jRAQufowIKOczyyo0BKV8kXTakKWYkTJkKQqHbrWw9RpJklCt1XPq31KF1tsy7pGTf+/fBmvRUeS529b6f1mCjiOcc+gw7FpI4jIQRRAZRCtk7vYjP/dqPYb7vfh9jj0FvOCcewv4X4BvPPKmA8JGONgigjSq0G5hAgXWYpMEydo4m/nNSwvh+CgohxLf+6B15iRJktBsd0hTy8TEBK3cRdRa89JLL/HGG2/wySef8NFHH62asXbXLyI4VBz5JKkIIg5RGl0u4UzoWSpRiB4d9Qo6CHwzHKWQxvrjglmWrTs59aSwUW59cc79+/fJsow9e/Y8fEyWgNYgCuXsg/v4WBPFD05trlegtebFF1/k2LFj3Lx5kw8//HBdzJgdH15otVrcunWLl156acnvza2rmNCXEYtWvjooNMT795DVG2Az3w8hCNBKgbM03/s2tUYLh2BRBGFIrdbA2gcvUdEyTkRW3+kaC6g49HHavBqNLMV1OujAE+dxGaKEYGoSXS6hSjHKBIBA7dHd71dTusunifabOOqcW3TO1fL//UdAICK7H3njAWCjHOzw6gV0qHHWYvN+vEobot0TZI0GWhw68oUmSimctWTnPqDRahMGIQ4hzSyNRoN6vd5duIX7uGfPnm7Guq/ymL/j3ydsTlNSqGIzDYxf+0pQkQ9p6ShEwggVenoZa4zpLsdOKXrZaHgBevorrNSvIUtBaVwUY8OozwGCEyFTW8NpjuOYz3zmMzz33HOcOXPmoeKlR2HHhhfOnz/PkSNHlryUIoKev4c4wFmUMUipjAqMb7enFMFIjFWCjmNUGBCNlmhfPou1IErhUGRW6CQJ84tVmq2lIYcXXniBY8eOrZiQkU4LUbl14pwP7qept3bbLXS5DJ0OogQVBYj2Haq85QSyhmB9r9Jd3tPgc5/7HBcuXODKlSt0Op2+E0dF5BnJTxKR/wAvv8HNOlkFG3VDo3s3EMErXPAbVWi6Ho2JA5wSlNaoICQeL2FnZ8hSi0VwonFiAKHdSVis1slyJSEi7NmzhxMnTtButzl58uRDJHlp1xCjKZqsgMNah8usL8LJva3CEhYBFRifSAVI2tBcPVG6k4tcHqfXxfT0NFNTU1Qqlf4HZIlXqlEZop5+ug5S33gDEDK9tfHvqampJcVLa+3dm6bp9iuOeBTu379PkiQPzV0SEXS7hnOOYKRCODmOikJEKRS+wbSOQoJAIc5iRiooEdzcPd9SMvMdi5wYr3wzy2K1wf35GknyIEgfx3HfhIybn4Us88pbaSQIoFIGrZEohjBEV8q4JPHVU86BszmRPi9nTDpQX70qZrWgvDGGX//1X+cLX/gCr732Gn/rb/2t7sTRYuoo8DeAMyLyPvBrwJfdFq34jSpd01hAEEylTLxvkmB0BB1olJacpqUwRvkQRDlCiSCNRTLrSDIAhQNSZ3AOOknK/bkqnc6DunutNYcPH+a1117j0qVLnD171nOh8w1TlMbldDCJo3w+WoLrtNGB8SGrwPjjk6SrpF1hGKzCw4aHPZidxL/eqNJ1znHt2jUOHz688jE2AwSnA6w23ftkOuTG1Du55yFksvXx76J46a233uLu3bt88MEHj6SbDmpcz5Z92mLu0ltvvfXQ36RZR2UZVEreDcwy9EhMUm8hKMLdu3D1qldwmUPrMplVqHYTEeX7UjsBUbRTIdAKEUtmLYu1BlEYUi6FXet6165dTExMcO3aNU6ePMkbpk45jLCtJqpcQjpNjFGk0R5s0Uc2S3ysNy75EES9jq4oXJbhcN6QunEB98qJFb+DRwXlv/jFL/LFL35xye96J446534dWLn57CZiIx3kRASdtlFRgNY+f6IrikRVIE3QoxHZ3H1UpQzaoLTDoSBLUPN3sJP7sfhYvXNCKgHiOjhgodYkjjNGSlH3Oy1I8nfu3OG9997jpdGI3corbYljtIBuNUl3TZDNzXv3t7EITiNxCScK16giZsR7MHj6GPem4fCbK37OnVzevdHOgO12m6NHj66qhBy5ZxHEiE1yJQztaIJGuIsxZTxJZJNjuqshiiJef/115ufn+eijj5icnOTFF1/sG5Pfdom0R+H69evs3r27z9gOkKs+iWaMyndekCzxoYUwQpTDpd4dDcZHPN9SeUWor51Fa02K8bumhWbq3f88706znTA7X1sScigSMp/5zGdo375OZjMwvjk5IjidTxaYnETCABWGyMSkr8131lc4WQtKYcoVVKUCC6sXSSy3dHdKsgU2WOJdnUOnqS8iUcp7Di7DxAYJQyDzJaKBIRir+ESaX6eElz8EFEkmWAfWOZJMyFyIEoUgtNsJ84uNJWXgIsK+ffs4fvw4cu861ma+zDgKfbmptSjnMHv3QhT6GPPYGCQdnyCNS962ds7HeUfLSHt1C6hXrjtJ4cLG5Fqr1ciy7KGcw3I4/Fq22uSVZ17pNoMJHJCYMoiQKvPEv7eJiQlOnDhBFEWcPHmSmZmZvgUg21bpLn/YTqfD9PS0b/XWB3r2tnfvCvKI8oRtk1O3fGeoEma04uNu/iY4UZgbl8ict3Qz63JSPbSzAIvpNprJMsdivcXcYp00fRA8L5VKTMUBSsAajc0yQIE2OK0xgYa4DEGe3W41EGfRYxOew6u0jwGKIMnqGdHNoJ9sFTYUXrj8McqofAZhMa5FMJFBhQaUQpVL6HLJFyvk4RoQ1N0bpNYnNFNCrHVe8eI32KI9YJJlzM7XqdVbS57PGMMe41BGY8MIm6a+Ab0SXGDQAmpiN4SRZ6R0fAMeNTKCiiJfEBNHSOaQbPV4fb/wwk4JMaxXrs75kT5xHD/yM1rrfG9i8e9AkeBuKN9cJzFlnz5RISs9QpokpO2tmRIsIhw4cIC3336bubk5Tp8+vSTRtm0t3X5CPH/+PIcPH17RspOF2bwqMI+P2swnOqyFQKNFMGOjqHIZM1KBMEKMIaiUUPN3AEFhySRAKyE3Vuk4Q0rQnQ6ixO9WC9UGtUar61ZJ1kGZgED7EmArPp4nosAEvhBCaxR+cUkY+rhvEKJK3jX28cDVe+juRKVbPO+GqEWzNxGtfGWST/+B0uAECTTaaMLJCZQxmHIFtC84CUZL0KhilEJpwanI92sWQYmP73ZsLlfnt+pGq8P9hQbt9oNYr3QaKNEEUZj3R3Y4FaC0gTBERbkMkw5iM5QJvOI3BhWXIG9+g02htjJ1rGjg3/vzdsdG5Xrnzh3iOF6Tl2ad8wZU/nPx37YuIUBbIhCfBLcrPEO7sUhrDYVHg0QYhrz66qscPnyYdrvNb//2b3P8+HG+//3v82u/9msPHe+c42d/9mc5cuQIb775JqdOner+TUR+U0TuiMiZ4ncD5+kuV7oLCws0m81uF7F+UO26L7vU3tpxWYZLEmyng44DxDlP58rLCpUCXfKTG7TrYJ3GOuVdGTFdi8o5oZ0Z2lmEUnkGG/98jWab+/M12nP3IE18TM/5GJ4KAjJRWHyLPxUGkE87IIpRcclb3Ern3E9AfCyS6tyKn3P5xNidQqCHjVGL3Pxdv3FpA2HgEyfW4myGMcoP/gwNrt3yzYRsiqqUUUphjGCbDTKncDallZquBSkCmdN0ssjLjOK9syzWW8wv1kk6CXRaSBzllpbn5jqtyUTjlPbJ2jj2ci1VIPCNd3x/BkWX8WAd3F+5+c3jTNd40liPXLMs4+LFi7zyyitrOt5Ziwt9OFFweVkwNKUCOFrEPgSRhyEeOt85siTBOp7IWPaxsTHCMOQf/sN/yM/93M/xzjvv8Pu///sPlee/++67XLhwgQsXLvDVr36Vv/f3/l7vn/858KO9v9hUS7dwRV577bUVX8osaaNcBiIE4yOE5ZBoYsTzJK1FtZo+7mc0Lkmg1cRlliD2itC4DKnO+qC9cySZ7hKvHb56LXWKRhqRYbqWkcvd1c7NK1ilcHm5r1MapzwX2L+Q+dsQxTgTweQeMAEujP2aDHws2RaWztzNFb+bzSgp3CpsKLzQanhe89gI0WiFcLSEBEFeIJEgJkBpwTabuE4b0owgNJ5ML0J06xygsGmGFY3IA+vKAR2rqGcxogJ63652O2Hu1jTOZrhuI23BBSFiAtDGx4lF4cqj2CDGjYyDs16uznY3iUKusniHlfBpYS/066+wGpzNcEHs7wPg/PfSxNP0WlLOOzPQ19JNM5tXDCvSZLAtG1dEltG7AxTVdn/1r/5VZmZmEJGHyvO/+c1v8pM/+ZOICD/8wz/M/Pw8IvIsgHPuT4AlxQEDV7q92dAbN24wMTHByMjIisdn18/7iqEwyLuLWcQ5gt0+gSXOoUsR4iwSBiAKqZT9wgBfqjtz2VtEzpOtk8xnrJ3zRoo3WISODWhmMRl53wSBqF3zStRmOBFkcgo1NQljvj2d5BavDUL/zoShT7pkqaeXadNN/iAatbhymWGvG7pTwgsF1uuGpu0WKsu6/Q18dV9GEAdImuIyiylFiCjUSNl7LmOj+X7pwGaYudu+MDC3ZtuZ6RYyOZdPU3eKRhrStiGOvHmLQLl2Nx96aH2oamIXevce1MQUzhhf1KIMTisweXFGu+krDW3mWQv498tpg7RWLpLYyeyFtSrdFfsrrALnLFaHXSZIsWZdXjnakVJu5fa3dJM0g5wZlG7BaB4AuftJd8QQ+B4xBw4cYGpqirGxMX7mZ37mofL8fiX8wHMr3WPTLN0kSfjkk084cuTIqse7m1cBhY4ib5EI3s1TEExO+Aq0KMImHXQU+sSL0d3dyFpLNHeLxPq4kHPQtkHXZfEFR9JdrBZoJJpmFpO4CNVp+KIIa5GxCa+MAa0VjE8gNkM7i1FQXFCSNqrT8NavePdIShUoVyBZOdO9GR2LtgrrDS/Y6xdwWO/CQ15WnSFZgtk95fmwWoESzNhYXgiTJ9Kc3ynD1gKZE6wTb3WiSK32NOki55pHADI0jSygkUZYFRK2azjjE6kyNp6HksUr17ExXH6uMQZrgvzZUn/7yrj3iETj4jJSGfH0shWU02pFL9sda6WMrdhfYRU4a7HKgOjcu7Rk2YN7ZRKQiSZz/WO6SZLmPPgej3Oz0awirZWLYcIwfEi+K2xaKz7wpindJXOSVkN1DhUaxOWTZxGfyDABqlRC4hiXJpCmSBQjUYSK47w7lQVlCNtzOBSJDbD5Iq13fEbUJ+jofgXFN5HXdaFsAjhsZQxEY/GBfZzFuAw3MuY5pTb1NfpKkwURNqp4V9VaXBAjeXUaLk8A9sFOTKQVWHeW+861bk/iogTYIWCCLoXM1hZx1iFxyc/KKsU47d16tMa0qmDxYSF8zL6Z+g01K8r4FUusXwekVqOSprdSoxKCYMX4jlfKb9hSGQWcpyrmpb82iHBBBFEMSvlkauTdY2cMVPuHGJ72sNHc3Bxpmvbtr7D6xRWZMjhRNFWJDMd3vvtdWs1GrmSFVIXYFSxdax0tNUoqIdlWKd20AzlbwjnH7t27mZ6e7v65X3l+vxJ+YMU446aEFxYXF5fOSVrt+GbVD3gsflF0JcrLbVVl1Ifac4UrIr4XQhBBqUQwVsG4BLKETHysyVpop4qODR/01pAHLqnk1pFq17yeVBotfpEhgtGCFFaZ8q4uaQKlCqIFVRnFhREWixOBwJDl8UYHuPmZvp91p1u661G6quY30yLWDoDRnvMchJh9z6DAb6x5VZhW+AZHUQkzUkIFhmDhprc4neTKVmgkYTd3WdgcXrYu32T9qHWH+MSsUp7+Z4xP6GQZJvTVGi6z2LCEmAA3NgkmIMsynNI+7KQ0FK0IF/q3Cn2aN9Oiv8Krr7667ms7ZXyORITEVKg2U55//iAmMNRqNS8zNKlVfS3ZzAqJM7SJsG5rwjaSdiAfLVT0HL58+XK3Ydbv/u7vPlSe/6UvfYmvfe1rOOf4zne+w/j4OM65FTOvm8LTvXTp0qrJswLOOVyn6VcPzk9hNYGPsQWxj5eWvOUhI6O+cTjOl22KQlUqOGfRgaF8/xpODEmmyKxfhK3U5FZScT//3yIDXmp4y8UFoa9GQnwznSxFshRlM7RLkT37Ie0g+J6gNopRYYSK85iU9tQiJzkXdYXOVDtZ6a67cqlRyzdPHxN3UQnRARJ4ul/B0yUMvHeTpkjS9ptdOe8+FxhKc9NYDI2Oyhu/CY1Ek2SeW92rdMGHkkxzwVu5YW6livI0MedDHMpZdJqgJ3ejXYZ2mU+mhrFvARn7sJE1OXfciZ8QvUJcdycWvfRSxlaT6/T0NJOTkyv3V1gFVjRWtG9a5AytFJ599lnCIGB0ZATnoFpr0k5cX0s3df57zJzxoaVs9c1hIOjh8DvnMMbwq7/6q/z1v/7XOXfuHH/zb/7Nh8rzv/jFL3Lo0CGOHDnCT/3UT/Ebv/Eb3WuIyNeBPweOisi0iPznA1/17XabcrnM2NjYI4+192972pVKIS4RRAFiHSQZrmiQYgKyIPQNSFp1JIx9VVgQo7XKLVdhvHGL+cnDLLZLjMepLx/F0UwCCAQjqU/IyIO+5EF70fdbcA4nPrShXOZdjDwepYLIVyhpg2lVyUyJTAe4tI1SBnI+p80yxIFWFteq0W+76V2cnU5nR1hEG+mn65yDrOOVaRgQlaN8wWhsqwnKJyiJS75xfJrC6CiIAwvaeAtZ4Sgnc2BT2llMaCxFSLCZGrSGUPuN0PHAgyk37vrNWSlIgdyTKTZTbVNIHcplWGfRZN7SVRppt3Chpxi6IPTFMsqgnMN1Wo+U69Nk6SZJwrVr1/ihH/qhdV/XOUeKBqewKJIsIypVUErnlO28kVVUZr6aMOuqVOLd3Q3LWkitL+f3BTKGNLMEZpOLaPNwY/EZRIQvfOELfP7zn+dHfuRH+KVf+iVgaXm+iPCVr3yl7+Wcc397+e8GytNN05RarbYkk7cq7lzz/TaVwYQGC2htfFZbaW+hqLwXqk09iT0wvk4/jvNpogIO4nQRZ1OM8hxOJbkBDTQS411SebAwBdC2g9WeIeEQX4UWlyCIcFr78kUTogINu/f7areRMVRhodoUpwNEFFoJDkfHWqRd902xl+Fpj/0VsHO3vQLVGhP4ZJYyBhN7XqzLixDUxASq3UBynjRhjFQqfp5WHpWIbZ3UCkkG9Y7GurwQUPn4bjPxHcisdQjegzG25el9+OSZUwYXRp6FkCV+Y3V54mxit0+MlipIEHqlnLbzpJsvJ0eg7QSXdrC1h3nYvcmzp0npXrx4kRdeeGFDHplzkDlF6lReMQraPChUyu+Ok4ggqoAoTp061W292skg89u2D9mJfqSl+9gJTGs9K8ktVbqDxkC3jUuXLjEyMrJ292r+LiLOVwYVia1cW+qKb1juwFPHghBnAqwJfUZZ4Xsf4IUSpg2SLEArR6MjGPVgETonNFPNXKvEYjum0QmoJjGSJj5hIoosLGMqFR/CGBmlM77XZ151gDMhEpZ8HNmEGJehohIqS3BB5JWz+Fgko1O0RHPr8scPEbo/NeGFmWuIKCTvbWDxrRsdoEuxj5OKQoLQx/BLFZwJ/PerjVd4AM43zKGTopXQ7CjiAJS4PE7vaFvD/VZM00YkNqCVhKiklfNzLZmJ0eMTSBSiShHZ5D7f1SqIIPDz9yRLECVoJTA2hTUBNixjxU+c8CXgE3TCMvc+OU+rtbTysJcKuNPkuhIrpVarsbCwwHPPrch8WhXWORKn6KRQa3QwYZir0B6di9DKPHuhMjLJsWPHmJ6e5gc/+AHNdoKzD47MnJBkm8wKKRgqPcyozeiLPLArVqtV5ubmGBkZWXt8JWmB0r7oB+WHB3puCYL1C8P5eKALQlxlDB3HPlYXl33FGF7pKptQat3D5K5rYlVeBeP/ntkH9DGHxrQX/BRaHDaIUFHk7ymADjBhQFYe9Za4NqCBqIzK2ki7nrd8LKGVf5UypXGlUV9NFZYoS/bQnLan1Q19CPV5EL+BWue8ci0UrdIQRL7oIAhxUcmHGfLvQkplr5St7Ras7G1eoRw4v6G21YNYbp71ziwkqaZjNWmGj8M76/MDpVH/ktvUd68TS2d0CkyudF2GiytIc8EvuvIoqjTiS7+dxaKxJZ/MNSZgJI758MMPl8zc2skeTD/+tXOOs2fP8uqrr65q6a32PljraFshcZ4aJpK36ExdV+s68QnvzAmdTBHHMW+++SZ79+7l4qVrdDqdboFTJ9Okq+z5A7FK006ucB+W6yAxMKWbJAmvvfba+kj0nQYEAVnu2pM3ES/mVUm5DC7zMVUTQBx7y1jodq1yOkCNjuKCiN3taT8ZQBzNxJdxeo7fg1iu+GgEI8lsXhcuZFEFLQW1wWe6nYgPYYRRfq8ANzLpWQxKewsoruQ0MuWtXB4IKg7Dh+a0LS8D3kmLc11Kt1GDIPAZaVGINjkVz3M1VeytHtEClVH/feZsEcGCMWRhjBodw8UVJtK7JJmgNSRWL+Vdd7nYeTw3ue/fCyxpPIaI86GENOd8Ko2OQuzoJM6EXvGP7/EhjaIpjzZ+NFPeo6GgEoLDKHjrzWPdOW1zc3M7djMtyqqXy/Xu3buEYdgdELrSuY9iPfjBAhCUxzyTBOikDumeJzQ6BuuEdvrAO96zZw8HDr5EZlPq9QZZZmmlila6yfHcpO2TrdkD9sK2VrpTU1OMj4+v2Q11LT+Ch0JJ50J0eeUSaYLp1P2itRkEgW94knRwQeiTysqgRkdBNBKElNMFOukDgXYyz+1MczdFSRGrgcjWQYQ0GvFVb2Qg7gGXM38hiUrdQLBoDWEJVx7zlpI2nl9atHfUyittQGyKpJ0lc9p6RwXtNDd0fZupn6qbWdelDEG+EJ1F2xQxyk8KiSIk66BbNd/xK03ACapU8huoFiLXIrHewlXiaHT8a+tbPuaejvLPVkrmfX4hGAHB09CKohttfBVaEdowxsfklfgqqcjzhQHffEcrVHm021/DiW+IRH2u2xb0+vXrXLt2rRtK2mlyXa48rbVr6q/wKKXrebj5PxXiDSBoJfRQThS1tiaz8pBCtWjK5RJRVCJJMzqJo5VsbnjBpQlZZYzliTQYbNHLlnQZ6wd77zoonRdEKE8pGhnzlmWadC0fOzLuY695/E/aTW/VpB0k8ArPLwZLrBLm5ut0OolfG+0Hu6eWB5n4zEJIxxPmRXt72Fr/dahCcXpyr+i8YQv4RRqEPuxBQYXIOcM5LUmbB65UUvfUsd45bZcvX2Z2dravRfStb32Lo0ePcuTIEX7lV36l33crIvJrInJRRD4QkeMbkdFGsNaKNNuoA7ZrgbpSGTU6jiuVfFGC9bxnWxr1JdrmwSh78uSoOIsOQ1B+oQbKojrtrjWbWkWa+dCCsyyhjhmaefLMezo6pxhCnlArqim09iNklJ8OTDzif+dsztN0oHzZuTbGc3xz0nfa8FNOSqUSb775JmNjY8zMzDA9Pb1mVkoh61yW//XGpPL4WG4kXb16lWeeeYY4jlc971HrvJNYsjQljPKmNs6x0I5oJ8UG7JOcjcSQOaGdLFVFaQbtNOB+e5QwCHCiWKzWmZ3tP51qIFapKLLSeLdMebNyME9M6VK7j1Maax1qYgIdR2gFQRyinzmIBBHOhASkSNbxSbQgxgXFpABvhfr/5XAiBGIZD6Dd7lCvN0kzx8yiIdDOW0K5pUvaQZORmdAT6YuacJ1zR8HzMvNm1i4uUcR5iMogDkma3j113h1+8Pk9zU3CEraTdBt1KKUYGxvjxRdf5ObNm3zve99bMh4kyzJ++qd/mnfffZePPvqIr3/96w91MwJ+DHg5//d3gH+yPulsHGuW68KMl1WaoMYm0HkXrzCOCXbv8/HWNCWwLd81TmtsVCatTPjvPwix5dGuO+rw7Rwn0xv5WCa/YBdbpsi9opXLE6YQSkqq/SYokDe7Aad1njT1ISdEekJHGjcygaRtpF2DIIY08ck45S/s6YsRNhwhVZpmbaH7kUdHR3nuuefodDp84xvfeOTYl15ZA68Df1tEXt+AWB4bvXJttVrcvn2bF1988bGve/3mrE+oiyZD+S6ABLRSYalqVGiRrjdaILW+Q2BqFS6vSCyVR7hxa6bvjMMCzY7bMGfXKiELIp8UZ/NyMJtSkbamD92oklmLjsueHoaAs77dn2TIxC4IY8+lLI0QJA1v5YxMYKMyWVTy98r5X078fffYaYJoFB1ENFp+hPe9mqGT5hVIDuJsHisP6vzFWVxYwsUjXpEC4GNPYjPvnhbkFeMTQiQtbxFlKdZE3Ws5USRRBWcidKlEo1btup7OOaIo4tixY1QqFX7rt36LixcvAvC9732PI0eOcOjQIcIw5Mtf/vJD3YyA/wT4mvP4DjBRdDPaLKy376pbvOc/b+grzawo7xQ4i05qMDrpwwlJGxeXUVmKDUu4MMaFJdIg9lZv0esYH0OYsPdoJ3n7TvyEkJnFAGuV92LAl28WC8X5jRMTYiuTuHgE8sXUNYiKkIPkHo7NfA7A5CXdJqSwoZ1o0rCCBIYgiEjbbTr5wnfOobXm0KFDvPHGG3z3u98tFGpf9MraOdcBfgcv2y1Hr9LtNzR2LectR6vl22sGYeSTZInkMX1HO8vXKwAOJd4gWs6wTDPIMr/mFtuBfw9E8/Irr/PMM8/wv5Yw4QAAIABJREFU/vvvL5kA7ZxDdMjMgmNxgz3PfbfAogpxB1i6vST6tbihSacFAhJFvm0fDuV8z1MVBEh5BBWVsEFMVhpHJ01Ei1+g2mCjCs5o3wzFgXIWh2LczbHYVBit0ca36eu06tRbloWm4X49YERq3S82E4MbmyIrj2Ljknd7y2N+0eIrmMhSXGnUx5p14MtDo0rumqoH2TkgCcp0FXTuSteqVdI0XSLEgwcP8gu/8AvdwX79OhUt72aE71x0vefnaVbpZjRIrFWuWX0B58BEUXeKrxKQLPHTd0ODBJH3EPJNVQIfQ1f4xBtRjJW8/NZ5Zkspq3UrDTPrS0QdUG8r5huG+aahZBdyuYq3rsqjpFHJT46IR8hGxrpyx/lxSy7ME6Da+P9dHusm02y3sYOQRn56beFZaXE0GzXa7fYSuT7zzDP8tb/21/j85z+/4ne0XNZsoRyXo5Dr/Pw8SZKsub/Co/i9u/fuw6H/f/Le7deu6zrj+83LuuzLufAmipItKaJkwXbsOHFSGOhTYaBpbMBBHuL0KX4rkrbwY+A/IAn8ByQPcYEGzlOQPDQuUKet4ZeiCYIUkuPITSLRpijJIkWKl3PZe6/bnHP0Ycy1z+HhIUXRoqPjToCgxLP3PnuvudeYY3zjG9/HEC1dtKSkV64fDmW6I+ca7sl0u+jWw0whGbzTINwGw9mzZ/n85z9P27a88sor7O/v63uqTmkV9AGC7uHPIEimf94LL3xYppTwnwQvxGEgDT22VnqQAUyM+gG9BjXrHWa+BUWFtfpGxZco61Ny80PFqIMpiJM5sZoySSv6aAgq0UtVeSZ1TdM0NE0HCCVDpnn5DFfkmz0HSzGGMN/OXLNBMcGo7gKSdC5fJsqYkDrLVhoQW2iJvF6ZaWEMzrl7NnEymaz//7hrdgxGdRxo9Wi11AdcDwsvdM0CV08OApYkhW+ietBZYzHnn4GioowrbZy5ApsCLvb6mTMmG40nTObEyRxrIi4u6QZDTJrp2sxkMQaSGGZ2iTEQrSWWM7zJ13sUabCOON1Y9wCQqH9nnEKqqVITfanYvTEZH1aWDIyMovHwsZRleSxl7EFc9Q+qSvU414jp/sd//MeIMa9/lmK47/Pu933Y399ntVoxm20QkqMNji4YenHrKkVg/WmtEQThkGn3QfM7M46sMXhr6JOh6fX9Oed44YUXeOmll3j99de5fPky4iYIsOp5KIEcEeG9nRVtp79cYkCMzQf+3fzrjzS88DA35+3L/5ZpP9q0QlIet3QH1DHrwHt8WeKMIbqSYEsVGA/dWi8BQCYzUlGpNUxRctbc4Oa+Z1ImnAHvHRvzud50zR7OJp21d5XecCa7SoyAoSScEYbZ9jrTJfTIRCX+xNq1MM/hbGgoZ+vaNaPOJBxVloN7EJ/zOKWiY4z/fgocTpE+xgPUjD7M9VBqVDdv4iTqyPbY9Y0h0+wMuBIKHYQx5QQnkVhNSaYguhIXOt1HUepeqOZIOcE6SEXNefkpeytHYTXoqTKkAMoHLow2zIKf5AEKWTNRYMRmjfKvR5aMxJztSoaWdNfEuLUiWSj052TnEowlil0fmh+UCnh0r/k57uPRZYyhaZpjda/jzZ+uHXyPe95x34fXXnuNT3ziE0oDi9ntA0MX9JrETCSRHHltPv+GwHrEe4ggcug+ys3TbrA0/d2H2Xw+59d+7deoqpqYLCEEUmIdnB+0Vl0khMSiUa3elBIRh+Sw+Lgono9VxPy4FWNkefs6tlJ5Rsl4nyDakMokeqxVdkJZkXxFNztLmTpwDhd7pR2RiL7SsdJx2sVaPlbcoHDCqlEqkUFIYnCu4KmNpZ6sVptgNmdWmW3PKIpisoZu2n5Ss2/rNIuNg44JG6OZUg6+KnyTZQMzNSqgdKkqd4IfFHR/4zd+g0uXLvHGG2/Q9z1//dd/fY+aEfC/Ar+fWQxfAHYfpGb0Ya7321cR4d0f/whf1vkgUs6rskJEA64vNKstCtg6QypqQjWnSA3JVwzlTPcrRbBGBxTQG1CAbadVzJ19i3eSGSl6A8/ZwRphcPUabtJgOx6KI4Up4a0hzbZzFTPooEZKB153oT9oqhqjJaewPkiC9RjvKY/Z14fJiA7vtTGmBP5bdG9/rssYQ4yR1Wq1hrkOLxk6UnO8tuxxQffmzZsURcH29jYxaVZrjKHw2UwA6HIj7R//FULXacWZoA8HWjNtrw7QzgijG1YzWGKydOHeYGqMYevs0zjv6dqOkCI7y/e391l12RJ+SPmzCMkWa7eQjzymO673y4jeeOMNTk3yhFIe0zWbZ2nn27B5VjHTQ/gwvlTPsqKiDA1OIu3klPqpxYgpPIdLIhHYKlY4K/TBrInYmQrM3K8QV+UYK6TMXFhnuWNmCyRjiMYi9Qb4EgndemwY65Chy408Q6xGLyjFhtSVwFMdck09PFZ4FCPy3vNnf/Zn/OZv/iaf/OQn+epXv3qPmhHwXeAy8GPgfwL++0fdpw+y7keiP7yuXbvG6VrlEMeGotk8TdzYhnNPr4cgFCtymMJhyhpjoBwyr7eYEr1CE2Lzvoqseb6163HS0wWDE1kLFyWBU+WCaIvMepADyGj8aojobL0kHIkUB8XlY9Cm6Agl+AKRpHxtJDdJD15HlbMsZT1Zf/YPOgZ8eK+Bfwf+RkT+3w++Mz/7evPNN6nr+tiDQkKHDMezBI5+H0YN7RdffBE4wN0N4J1BpwcTy97RDkI3wM5+1IMywBAOGAxDRn12Vo52zck2OCv3nUpreqWdLTmLN8I713d4++23H/idHcLBz4bs0pOwB5Ouj4m98KGzuN+vq3njxg0+tul0rtpaTL2FSZnbWHjwm7DcZ6QamLrGx4AdkmJ3RUm0NckkbOp1tl7DHFq3gjOBc8Utbvan2VsZNqdCTAbvBgr0dDM5CqcUWSwapnWlnM5cTiWTM27nidbh+kYr1GoG3VK9n6qJll9ZrBkyVGWMZtLGUh25Oddc4RjvuTm/9KUv8aUvfemufzusZiR6Yf+HR92bn2U9aF9DCLzxxht8/mwJyxVgYL6Fkag3HALTOfS9Bjlr1desChRNo8wTl7V3fUEQFJPF5IpCD0yL8OL8KpdWz7DXGLbnCRFDTInatOtqx2YWzDoNlrT+26SU98gS6ikuDpkWONUx0KLKlYsGac1yR2zYEFyJMZayOuCxPsoY8KG9vjfF/DmtxWLB3t4eZVke/wARTTQeYr3zzjucPn2a6VSTj5Q0kNpS7XgSBpL2TXaWulO3dj2zbeh6CEmytoIOQcSsHtgGg3eRlAzWaiA/brXB0qWKyoDYmvl2Td+8zssvv8wnPvGJe1QP+yDrRMxgaAcoREjGEjmevXAi4YXXX3+dF3/pl3IJLzpGm9+BcicVVpDZxqGbJdEOA+IKej9TlwarTau+3FBMDZ+7o2RureHp+r11JnRrz7K7D9vmNiarkokYWiaUG6fwG6fZaQNNP+QyUylskstk8SWpnOTsVWfyxTgolFwvJjf1clCKVh1oiyPWHkdPzvt+2T+C60GUsStXrqgvVAwaBGebaqkUo4ZB6/SaTqbrUW+shWpGKmq6aovkyrHFQnQFzufR4fxVsknTnyeqHbxVqtHe0rBcwdzs4KzuqUFoqGCyQShnxGKiwkXZ+wxEA8A4nTY/rSPeIgo1YDXwOj00U1FmXBKS9YgYqsn0gft6UsaA//3f/32dmR5dklRSUcLx3mSHD+EQAm+++SbPP//8+udRMgUrKhYbk82edrBstXJYthk66AwhmDW80Ad9zoj9dsGu4YZwH9GbdhgdX5TRMkTLxYsX+eQnP8mPf/xjXn/9dUIIhx4P6k5s8u/UIJyMPTAkOOnshd3dXfq+Z9Mr1pbKGpOVoMbRWV2iGWU50cmlGOhEZeGa+rSm/7bAGFH9g7wSjsZM6MoNQlFRuYHKNqTc6Y4SOV03BHF0pqQvpkhZEV0F1ZTp6XOE2SluMyFQ5JI2N/oyrrcOsHkKLWHBelIxWX92jCVYhUiqyeSua/C4NvHnse5HGRurl6cunAeEmLVoc6dEA9zIDLEmD5rk5Sy2KBiKKV4Goi0Uq89moDLyniloqi2Gao61hieqm+skthkMZ+qFNm5MyeBqTFkRbEFwJb2v6aoN+slppKiR0Y7JKnE/jA4RGZ8Xn/31rCX5eo1FCtAbHRku6vvv60kZAxYRLl68yOnTp4/dVxlHp+/DYBjv8/1V4MqVKzz99NN3HTYGVQbrgrp9DMnTBsXGu2F8acGQWLWGPhwE1D7kytVIdoxgLWB/P3hhHA23FsQ4hSIizGYzfvVXf5X5fM4rr7zCjRs3EBEdR8bgMnTWtyHDjUo3HK/RRxrTPczTvZ9q0UsvvURs9hXv86qlkAfn89gtB7hq4ZGUGNqG6cYmpTeI9xSpVwpWCspgQOfhoy2gniLG5cEHzy9t3iCJbubFU7fA6iy/c5DE5kw476oI3nkmG9vsmprlkEjjATCSpl1uqE22NPhmGcIxQADrgOuLUoPPketwGF44KRkR3P8wff3113nxxRdJuze1XHMO50bb85SD7ljqo6PUmUqG81oNWEsdlwgOL716leUDLxlHrOdgCw2Y1vGxjT0cgSSGJ2a38V41MwqXEKO43DoRzRVTTELrN+irOWmkkVmLcZlz7UqkmiFJ3X8RIVmnnxuzNlj0VX1Xlqu/4uSpjBljOH369H33VQOxIcX7Z7ptL1y7E7hx8w7PPPPMXT/vgyY7mAwviKUNqqc76mUYI6SoI+N9MAy5Wl31JpNNlB641xhCNOtm29G3GyK0QamnOhKu1e4YiI0xPPXUU3zuc5/j5s2bvPrqqyzbyCAltzplbIgEsHpAjF+ex7WvH/qRfFwZ+u6777KxscHGxgbL9zrEFZQW6Bs0s81vYwy4KQKRMNnA7t+mMLnkF085LNUQQHT8M4kFAtTTu+laRpi5nl8+91OaULI96XAkdGbBEoHaab0jI35sVM1+urHByjqWqzsY6/BZ9EYFz6PivaEj+cwfdsofFlGjPQHqyfSea3NSy1A4Puju7OzQ9z3nzp1j9dPXkKw1DJK5QZa1K/PhA24yh3ahJX9RYocBYsI46GSS+1aa0oRikisaDQIGobCBT5+9yt5Qs1n1WGNwEpVWnRylUxrZGHAlZuqPswQ7RWKiGql+Oau2Lum+9g3iZsrZLCb6O43Q2xJjhOoh9vX9dAs+Suu+egU56N4T4Q49rwmG1WrFuafunWLbXVkwQsw7WbqeGCzd4BU6yN+Hrte96QbDMOjvajuDxMQQDUFMbqYlqjx62A1QH0Lmlp1Zw1Djx+mjoRkMm4eKkrIs+dSnPsWdO3e4cnOf3m5RV56Eg9Sh6IRdU8YO72vf9x+9THdcR8vQGCOXL1/mhRdeIKWkNjwjb5LDPEpYO+mmACGQhk6t0DNNyxpD56b0xYymPLW+oQc3hdE/TV8IBEI0VF7YqnrEQC8qmBySBTGUjozlxfHNQy43XOHxW+foo7BaLkgxEp0/KE0lY0CuWP/W5DwCFGWFPYYcf5LhhaNYvcjdhoWpzxoTh0Z41xWMgZGKR0oa0Maa0atSW+s2iEVNZ6da5osQbaluDge/VLOfPEq6UfVYJwQxRFG1KhGDOrooPewwt9ZkmCOWU9IIIxhI4/CDyf8vBlxBFG2oJZRN4YrqnuplvBYn9TC93xJJjCTao2L841o0iZQSxWTjnp/dWVmGZFh2RvstKWGJ9MEc6r/AcpXDnIFVo79n1Rva3rCztFQu0Q4Gb5QV1A33cnCbXt0pGLNcYMhB97i1tX2K2cYpEMtquWDZ5UwX3fvjgu5HOtM9mhGNeE9ZljR7txBr1a8qdEgxRWotN/tlqyVHDrhiHdYazNY52HsPsRZvI4viNN4aRNTvFUkEV2OScvvUdcDSGa/eakA0bm3J04heuFK6daNOU2N7gD3mQQnrLH77HG65Q9c22JSoikxpq+ZgFXQfN2cwBeYYLHdcJxVeOI4ydu3aNTY2NpjP5wzDQEqRwqrmbCwnSDHFOOiHW9p8DN1d1vQy3cSs9hBj8d6yL9s468AlAgUWobdTTBp9fcnX+4BBkDCEqJZOXSwIopn2tmtzgM40sdEwdH3YG3o/pRyWGd5S+EgFzTeyvKdmwgbDYPN3pn7/fT0p8AI8IMslN9IwWsnFoApsR567WPXMZ5PDXo7rFaLBGVj2BowQgga09VfAaNLVDwnnLaUXFktV+mt6vY9DhJu7NtPPMl1MNCifOtQFWnZjEE9ruj1C1tS+dzUdVN0dquoJEMvu/h7VpCdabaRp9XxC2AvGmLvghbZtuX79+hrvGVYLlfGzOm00+GrdoHL1lDDdQsopGEufwBYV0aAZU7OgtFHl+XAk64mm0HLeF9q5Nla1aPDEQx5ZBmFInigaVI21xKJmcDO9wXJQGW9JDmXMIoJMNplUGsD3Vq1OvTjF+GTE/fIEky8rxTSPWSc5IzocdGOMvPHGG7zwwgsA9HuqYWudV8bAeiDBalOrnpGqWXZv0IEECS2SAhJ6ilL5u0bG/TUqu1lkGllmkkRjCb5Wapg1RLFEcQzRkcRhrCP6ks5OSbbIEIe5609mbev7Lia5fFb8NhmLuCLj9PpdSSIk47HO4Yvj2SZHebonaV/vt9IhfvRxU2lt1ykG770O9x1pcIWMMvXjpJkYhpgZDCj2D5ByZ0yHmSJ7S6Ht1RPPmMzBnkaa3rC/BJB7Mt1Fq/f4chXXmG9Ihv54OJq2G5iF2xij48TVdBtrYLlqCSHlOPFgXv3Psh4rvHDp0qW7VIti1+GcJ/g6ly8HMIM1gqTIUExoyxlYrypP1iMbZwFRxX/rcYS1RF/01Rp30ttHA6ryOiFERxSv02VJXSUMgrdCkwwLM6cvNrJ26gFAYRBVgkyJIQlSTnEGJpOKpg8smpYUI6NMYHAlmOOx3HEdNTA8qfDCG2+8sa5eAEK7gOwzJ2uOFzlTBEQIzmsDMmdQkhLMtnVEOCt9TWjVtomU5RnH366wQeemetChHFCXs9FB9N+QvOdYlkxoii3w9UHQzd+1UTRSxJCKSaZHaeAVDBICMcNeYxA+zMs9uk7yvt5vpXzYGdA9OrREhP1FS1lVjBd+dYTOGxPsrQx9VC3rIeo9FZNit0PQQNkP2lfxVmiaxJs3VCCpdpFpmSidYEnsLC07S0sIQnPkdzWZ19sFz85ShXJiOpiCO7pC06rEaP7/LloGptjJNkMI3NlZ0DTNych04SAj2t3dpW3btWpR16xQPzL9kutjR5JuRlEkgbM0xlNMVVTaOJc5sha8au56AhPba/NqPS+v+FvnpqMkjja/jMVZ/Rfr9QJaI7g8v2+sYTAlS7vB4LRxok01AFEcGmiTRfK01WRzm6Io2G8awpBFMjB4Xx6L5Y7rpMILcLCvI0VsrF5EhNT3mHp20Agd4Rpy3Mx47oDRQOtLcAXJOs1+nVdDUITCqltvchVqLKoQUGdrYrZ/EWzWWRWigDVWcVjAO+WXJkkE41i6DbpiI7+fnDcbxSxFEn1CGSkSSZmbi7WkpJh9wGXfu+q+1+b9hl5O4hIZm6BCPEIbu3r1KuVkUw9AY4BEMxx+rv59c1fx26aFdshcaRENwFmgfuiTWjiZxBAS79xUVsTeyhBDwjlYNNq78U5oep00Pby6waj3GtkvLyrrobuP/oIMfYZOYiYuGTop6amp6wlFPTvW6eUjHXRH1aLDxnbtck/1FsbpoMPNNElrNa4hRsqqJk3m2rW2Xg0KywkigaltWZg5ghKmUza2RITeVERbKBgu0EdLwtGGguVQ4G0iSMFYPNosdG0y16SzNctiU/E9RhZEhi28JxRTsJ4YBoyxTDe3GWJkd7kiCcd2tg+vkzwcMQbdo5qrzf4eVNWaKaCPHb9W+fBKad00G8rpQdCVBEVN6leULnHbnGJwE4LonieMlqWmYHBVJtgrLijW08eCJB7vEsl4kkBhZZ2RK46rNL6F3yJaDZxrcfqktMDOlMoJDz1BUC3gQ5xspf/d/1Y5yft6vxXkoOo7zNWNMXLlyhXq6SZJNBNedgX9cJBWhpRlpw1sToT39gztYNHZo4Qk7XpFNCsNISpbIcC7O4DR5w8RHAljhEmZmJZC3yeGI2hHP6heA0aDfIoKbyw6cyz5QoYODDjG5hn0ydHGPEbuaj7/+c8jIvzt3/4tn/vc5/ijP/oj/uEf/uHe1xLh61//Oi+88AKf/exneeWVV9Y/M8b8N8aY18wRd5DHMpG2Wq2Yz+dsbGhXc32hc7mumaRmHuOXX9+lpR8iZV0jriQVWhqK9chkE+k7vBUGU9FS0dh5Lv8tQYxieZLFZ8TQJ5/JzpkAHRzGwv5QY13WfRhLYH03RAz7Zs7KlHqKjyaU1mqAz5izKWtwBfV0SlHPuXXnDu9cvfq+mrMntQy11tL3/ZoiNq6+75RvjRxgf0cqmHFU2uTJtDTZwDiH8WUWngmUpWUwFQFPY1WTOCTtgDduhojNvS21XTdWS+DCJUK0+rfo0AxG3++BjY/ekI2d0FitZhQaGkloBqnm+WAotFIylrRujH6ww/Qk7ev9Vkx5YElEq5G8xsZ4tBOFCpJlEM/qUNMqRHVuLjx4m+gDWLSySKIDDzEIQ6qRJHRdZOgDTScsWkPtD5xAQlSgY1YmvFPI77AMZNOPfmx6QMcEu0vNdkU41lctRAHj8DnTTaL9gS4WpGToo1Y3Gxsb/MVf/AV/+qd/yle/+lX+5V/+5R43l7//+7/n0qVLXLp0iW9961v84R/+IQDGGAf8Oer2cpc7yIcedEWEvb29u8YLu7bVG28MsNbedWOqYj90Q1CcKAuMRF9rI8xYlVMsKuxkrk0VNBiKaNHY2Nm6wzpiR1ifoQUtPxd9wRBtdpwo1h3t9WGYu55JEtFvsHCbGF+wVszCMhivY6NoR1Uw+LLkYx9/lhACr7zyCnt7e/e9Niexyz2utm3v0lyNISBZu0DHpSvVpPUFI0wzmoGSDy5jnNLssrGnjPdElbWFBUaXZkOiM2r3k5NW7WTbbEwqhmZwLAf9fd5DNDXW2nWwXR+o+cyPtmbhtzDlJHuzqT/bkBS/TUmIYjVAOId7nyxXX/vkwkb3WzFDCxij7txA13W8++67PPPMMyQ0Kxyijt6uuoPg1vVQecVp95dCVUDpkvJtE1hrGILoKH+Eto20beLWwqo32gASI0M0LBsNkv2QSEkIQYP4uJat9kt1ut8wRMPuyul0m9zbdEsCvauyVVdaV8WCoUtKKR2Sav+++uqrPPfcc/zWb/0WwzCwWq34y7/8y7te7zvf+Q6///u/jzGGL3zhC+zs7HDt2jWA/wL4sYhcPuoO8qEH3atXrzKZTNYllojQrJbgPIMt6IspXbVBW27QVlv09SZSbxKTnmplWd2VnYwBTqxX7yrnNfOUcfor05SK0XHUrDGaJIYheqxRPU7MqGRk6FKJ4PPdmC+8SD41M+ZnPSszywLWBx3w5DQbSkkf47yqiT3//PPrWe9Lly7dNet9dJ20oHv9+vX16T+u/b09dJS2oBVHbwp6W9EVU9pqi6HaIIjJOKlTAlKuHlI+zLAean1N6yyVGVSUPjNNeqfNGmP0ROxFtRBicpoJR4e1WfovalMtmvLgQD10z60pb9axJNPajLJPjPMkXxNjUAFsq6Xvgxqjh1/3pLJS7rdCVP0EJP+NOkJcvHhRm6p4rEksOs2Iu0Nf9T4oK8FZLf3rQugH4fayIkToe7W/SlFoBqUHrprIMug9PAS4vTB4k1g0hqFPxCA0nY72tt1BNbm/MsQoqIGMGpZ2QYP8EI7j9Obvn1FnEE2edGIuJJdlJjUsXr9+nQsXLmCM4aWXXuLLX/7yPf53D3B8ua/Ly4cadNu25datW2ulIVAlo5iEEBMxpZy5jsQsoU+wdDX7fpNiurHOPEVGDm6ZH4n6aMXARqGKXwrhWzpqpWxl+k9IZq1a1QfNhkKyCjkMljLH0CYWCGoLI3LwR/FL1tzQztbEPGkGqIOw89iiJGKpJ7P15x1nvWezGa+88go3b95c/+wwL/Ik3ZzjgEtVHTSTmtWKEAbiKEAP64pgbGr2WLrJGYZ680ASM1+D5EodtzUWqWakvmXmOyJQOL2DewrNhiGXjgaxpY6HRxhy4I3J0g4uy2QYhlgQKO85UNdBV1S3ozPl2sRSA7TFljWmKIjGU5bVAx0gxnVS4YUH8nRHVo4pWJoNFosFi8WC8+fPA6p1ohVldoQQLfVBy/9bOzG7PsCsFBatzVmlEIOQUiRGIRnH7ZVnvy+IyRKDuqktGsO7t4RVpx5qKenz+iAsVwdA7aLNUEKI3N4JTEvVwRYRVi33DEgsOoO1Qi8FQ1J9iCRJg25kDWmtY1Beo9PL0arnAY4vx11cgQ856F66dIlnn332rjeidiY61WKNwR5qsqypXnnePc5PE4sDGoreKJmhIJIttA3OwkoqvI2EBMGrcV0SFcXopdLy1AhDcjrmmSXH+uiovIxXh2WoSeiNnSS7vmaM8tB1Uu6vLUlJ1txNEXDO448Ez8Oz3tevX+fVV1+9x730JGW6I0Xs8BeunkyYTKaKjYroIMt4E8uI1QtYy+CnhGrrUPMUwKynwFLWz3Desxu1SQpJ5THRGy7ESJvKbHCo7AVnwVmdUOujo/QHv6KLBQP5wD50oI77OQ58BFMw2BLJM/diPTEqrW0yff8sVz/uyYcX7tFLATC6d60Ua0eIw4F6RApBg+vtrHfeBxiGhLM6adb1isdu1eoAHaMQBh1KCiERUQ69JJ04u7MvnN+OGAOn54nbu7CzELxLdL3kTFlXmwP9nX1UzKqPlDmzvrOw65+Pa7VSkZ1WClatUfOQpCyYPliGnJwhcO7cuREqIITA3t7ePW4uD3B8ua/Ly4cWdEWE6XTK2bNn79rAqqo4e+4JZrPMRjCIjSRfAAAgAElEQVQcZB656dT1HSbftJ2fEcsJByPBiQGXO80KN9hqqipQYnOjzBNjdmARvZFC0JcwRhswdamEaeu03M1xAcGwO9REMmPBaoNNjnw2ET1Rg9PAG6NqMNT3mT4DPXA+/elP89RTT/HDH/6Qvu/X1+YkBd2iKO4RNDHGMNvY4MwTF7TRtObCal1ykFWiN5crCeWM9WEriWC0GhFroZ7h6lpxOfFE8Qy2VD+0qF3pgCcmFUhJOAonOK+cT8Hg78pKDU0s6aQ+dKDm9yes3yuoFkewxfo74bynqqqHcsWFe3m6J2Vfx3WcHKtknL4zNW2fsM5z6tSp9c9jMvTp4HqHoNQu0EzXGGhaDY4hCs4kjAy5sWUZhkgM6osYhkiKiSEmCjMwq4WuTWzUSWGJfcNildaDFKtVoM8UsWWnATwlcoYs1EVid6lQQtPefZh0fa9TZ3mc2+YqehTUGTV9BfjUpz7FlStXuHLlCm3b8s///M/3uLl85Stf4a/+6q8QEf7pn/6Jra0tLly4APD/AC8aY37JHHEH+dDqIGMML7zwAm3b3nNqWmvZ2D5F39as9ne0HB0J6UnWDAK9GYTOVtQFSLt/MAtf1KQYMF4x32g8QxIaW7GO5AaWoUD1xIU2OLBmDbx3g2NaCX10ODN2LjVY73YVlS+Ym5ZRbAV9mdxcyxSjlLDW4VDb7eIh6EFnzpxhe3ubf/zHf+SVV15RtbUY73tT3759m9/7vd/jypUrPPfcc/zN3/zNXV/4Q9f8CrAPRCCIyK+/75t5hPXcc8/dd/7eec/WmXM0iz265R6jFp+Mkp1jpWUMg9NrZfslgtXrmauYcX+Tcep1Zfyh2QihiZVKaqZEAqJ49lsNdoNYSptytptNBtGXXQWPpBmbZYMh6vsz4yMODlQkkYzNAugPPkyPrpMKL4zreGVAlE1EwXLV8Nxzd2utD9HhnBCNwRph0VlKp9+RMeh2XaQsDUOvAw6rTjPiGBMhCkMXsM6RRLBGGSUxWcVjo8FZ/XtzkqgKoe+Fyhl29wLLpqDcgK7LOrwGnFVooTCJELXS3Vve/blCjFROEzVjhFXOhJPAEOxaVxd0Wu2P//iP+Z3f+R1u3brFb/7mb67dXEANBr70pS/x3e9+lxdeeIHpdLputIlIMMb8j8D/ATjgfx7dQR674M3hVdYTts6cVx7uOsvtqev6EINAIYWlOKSc5GxUGCTTfJwjpUTlI0My6hqMoNqblmjKbNWtds8hGkJw7LeesrB4pzJwYNYBNwm52ebYDxN6qjwjbtbNNZGEserq66wF98FuTOccdV3ziU98gu9///ua1XfHq/J/85vf5Itf/CKXLl3ii1/8It/85jcf9NL/lYh87nEF3Iddk/kmG6efwDi3rmDsoZs5o/J0pkB8rYyVlAiiWZYYx9C1bE6UKH/YiUPEMdgqv5Y2WkLUpsoQLdNaTSoTiu+uq5i8vzFZ9vopbZpoI3WN9Uo++GM+UBWiKoriobNcgMNjwCcRXnhQ0F30ej3wBxN5SRS+iWmUW9Qpsv1VhvACINA0iRCTQoBDIoaBeZ1V3zKNc0y64lrVzLC/UtghBGVAnJqrUaxBg68Blo2+36ZNa9sdaxLWCMtGKJ0wq3SY4q7PlRJBlI5oEG7vHXxfumDU+j0eVONf/OIX+cEPfsAf/MEf8Lu/+7uABtvR0cUYw5//+Z/zk5/8hFdffZVf//WD21BEvisinxCRiyLyJ+O/P7aJtPv+3Frmp86yee5JQhKc81jrOBjNzJkSQmMqbDXBWE+UhCknpCjgPLNKqT1D3mARS5OKNb8PIBr9Yoz+R97rzRki7PclIkpBUhw3a3EaQxcLVmnGMk0IKMvB+hLrPCaLoXjvH4kEv7GxwZe//GX29/f5+te/fuxjvvOd7/C1r30NgK997Wv83d/93Qf+Pf8ZyxUlm+eeoppvZSjpoKkGB83RBq8NshRIoUd8yZAiXUiUlVPVsIzzGqAVbXjG7BI7oJ3QIahEoHd606cEq8EfVDD5z4h8BPGs0pRlmjJIQTIFYjzWeVxR4H2BKwomH+AwHT/XSYcXjsN0BUvTR+p6Qn+oITUEaIOnG7RRPU6MLdqDoKuQDhjRoGitxxcV+3t39NWznZKkSN8NI4hMEri1p3FgZ6HBdxgSq1bYXyTFcwWWGTZYtIq/F04DM2hg9RYmZaJp7/6sIjq6H8USouXW/vi5lPkQMkwpPD7Y6OcedNe/2Jf85KfXmW9tr2+Kg8xDlaGs83R+ivUe6wqSK4l9SxCLc47glGsbo25skCLLxgl9sPnGFy1XI/S9UDhLSNlxFKfB1h7cmGb91pVGshocq1jQR08UbcrFII8UcMfr4r1nPp/zrW9969jHjVQVgAsXLnDjxo37viTwfxpjXjbG/Hcf+A09hmWMYbZ9hvnZJ7FjmT32r8b9FWFl6zx+K0Qsfdfhp5sUZUErJc7ouGgIwkCpOHGeQsR4vFPMUXmdAlljOSZLl4q1CIshU4QPIGfA0iXHsrc0wTMk1ecQoCrfn5d7dJ30oHtcdSoCy7bHFZXirod+3AeFd7pgmZbqaSboBNkQ1GhSRPmzt24PtJ1way8Bjo35BrVvsHFFDEn98RIM/UDfD5Qezm9H3rouWKMjwlE0691dJowIxsKqFZouEQOqPrg/0DZ97r1o1uvN3Zxe0KbZuhm7NjJQCLMP6iRxuO/0OPb1sYiYv99UFuTJlo99jI0zTzA0K3Z399al3igmjlX1rmgsJg06Nuo0SyqckqzFqHDJIlZrbQUwGnSdTraUlaVtE00Hq0oVjQKw1xacnvbEMRvSp4797TUDwlmzJvnHKJTeUf2Mo54/+clP+OxnP3vPv//Jn/zJMY++7/ovReSqMeYJ4HvGmP8Qkf/rZ3pjH9Iq6imurLizu0fFeKCmg+zBeqSaY/qGMOj47SSPE5tseW6ARV9AaTGoMWE7qMOA8VCWSp7vBmFjVuD6lmQquujZriMmHhdwQWEjMg6oDAhQ+GjyCALkh5OMk9QgHddxidKqh07OUJQT4O7R2zbrLMSo9CtrDEn0HnnrButsMUT1KT1/JnFtHzanoiwEO7A1K1lmD4MQIkW+d09vCqtWePq00Ae4/A6c3khszw1tZ2ibQaufTri1m6lerZrWtr1hLooXWyV30w8HBpSrDiI+NwCVNeOdDmN4q4HXmISk0aHi8bBSHoue7vutruu4ceMGX/jCFwAoJlOu763YPnOWoVnmDFVFp8XojHZh0eOn8ooDZUnFGIUgDuvyBclNr14KXIIwWKZTsiqZNklKn3LpA3t9wWY1rCEJxZBZ36U2Nwoy+oG1lrK0D/U573dtRNSf6gc/+MGxr3P+/HmuXbvGhQsXuHbtGk888cSxryciV/PfN4wx/ws6BfORCLoA1jqWAeblBGJHilnbNk+nBWMpKktY7uPrKTEpWayqDKsm3ym+ynRAdRPoQqWZTmdxXsc+rTE4pwDVkDSbvrUqOTfrD/pmB105QLFEhSVkzWYovHvkfT08aXhSGmnjez4OXthbJsqyXI/Vh3jw86Y3OKOeEP2gVYc3yql9+xbs3F4hUjEEoe0SN28nVq3jpzcSQ4xc2C6JUjKve1bNgC9K3T8JLFfgvVLNQoCNqeKzwwDzWtjdDUwmnraHO7saIIegkq4xWZomMCSHrxJ9Vh9rephWsLcEcZY+elxh115qKakLxprmmIPA42qQfuh6ug+zfvzjH/P888/fVcaJQL15mo1zF3C+uDszMYYhS+xFMYQwEMTgbdAJlZj5mEkvVDNkwnYUglhWrRCCoS4VPG+HnP1YQCyrPk9LHHovjFP5a2qpoRdt4k2qR4cWHuZ6feUrX+Hb3/42AN/+9rf57d/+7eOeOzPGbIz/DfzXwI8+8Bt7iPUogejwsmXN5rmn1F/MahUzTow1yaCUTUtICXElpVNnieWQtW2T5iU6eaSnXxKj1t3RUDjwVuikzodzIIaBOyuPNWZdxYw0Xa1gWP8s4pEYKfz7D0Ict46S6E+a4M1ReGGxWCi9EptH3XVadFz9AKUdMu2TjLHqPXX1PWFvEekWK21wGVi2iY8/AX2fmPmGt2942j7x8ScLTm2WOOmZlwvEWJo2YUSVyeYTODXPg1UhYFA9B0RY7HfsLJS6aZ2K7AzRcv2WEIIGT2uVr7vK+O9+A0YMXRxpoSq0nkSdKgTRgY38mR8XvPChY7rvt45Otoxr/HBlPWXz3FOUk9kB0z1Ty0ahcFfWJGMpbE8fvU46iZYAKQpDzBbKCP2gs+B9gEmlQhbxkK6uNlgcq6Fcg/+jDqfNfwRDG3Vk2GcGwwddhzfw/dY3vvENvve97/Hiiy/yve99j2984xvjNXrKGPPd/LDzwP9tjPkh8M/A/yYi//sHfmMfcD0MXn94jaXr2GSbzLd0HFj71zRNSznbxHhttERjkdgpST1bp6eUCBFWvWL2ImTbF2Uw1JXRwQgslRfKwlE4y2rV8d7+Ec51Llls/m71sSBmLKN+hMP06PpFgBdee+11rPOQm5OIuUubtg8GI3HNIumjSu4WHvZX0PXC9fd6tutAXcKkVFigdD1CiTGJ2guXr0bKAi4+U3F6e8b5zYauW/Lam2HN9Y5BhyXevh6IUTVwnRVu3WrZ3U/0gx64pQ0MwbJsYVIk+qblVLGg7YSdPcVG9lcqvNRHTz+MglcwJHUjltxDGGU9Twy88H7r0qVL90y2wN0bb6xltn2Gol2x3NvV8WERBnJ2Yj1d21FPSlKTA26mnAxR/bJMVP0bYy0xRZxTJTIv4Kx6KmnZqqdanwxdKJmWkcIG+jAQfUUbPSYZLAFr9YZ+lPVBgu6ZM2f4/ve/f9xrXAW+lP/7MvArj/RmHnGNe/RBMt/D+2qtZbp1Gl9PWO7u0PUDxpo86qs3WTcMFIVDskVOihooteHmIakotsreGqaloyqV6uWsoQ0F3iXwlvl8StO1XLsV2d4omRQHHemQPBEtk10KlNWHk3+cJHhhXIf36NatWyRT5QEi3eex4h6XDhFAMzii6H2mZpGGJoDrhCEkLr+95Pln5zQt9N3ApOiwbs4zTxjevZWYVspGuXFbOLtlmM6mYAYKs8vu7oy3V4YLZwxPnbHs7DnaZiAMgjOBFYk7+xERy87OwN5K2JiuSOWMxSpyyjecrgLIhN39lN+3YLwlRssQUp69kvz/6kzc9wnj7w26H1l44f3WnTt3AO5H9L8niyrrKVtnldcbY9TxTGMZojIcXDmldKOfkT5nNThitnVetpbCqwBOXVuWXVrzflXm8eC5o7rUnVXJ7VXNMkyyZbTLXEJIMjCdPNpp90GD1UdxPWyT9PA6dl+rCZtnnmBvf5+qUv6tWKd7OwwU9Yyq0rFQyZ3N/davhcpXPRhj8xiqUZuVqIpmQWxufOpjJ1VNVdfc3g9c37PsDVOaWBHJdjFJEALTnyHLPbyvMcZHqoT+M9e4ryLCpUuXuPDxiwcSqag+yqp3rDLntQ/atFp2np2FoXRaUQqQgrDXanJUecPOnZbCQ981eFdReB0L3p4rRruzSGzNhJs7kTu7kenEM51t4ezA1nSFJWVIDxAw1rBatjRt4M5egJToej2EF0vhiW3h1k5is+qpi4GNSWLZ6ndWByAUohxi5ukjqg0TIAxCN8jap/aoXc+JgxdGAezDko+H1/2oZtZaZlun2Dh1mqIsCCHSdR2u0Dn8SYlSTwTaYaT+5MwoaVMtRC1ovUncvLNQmTiyK2m2CU+Y7PMkmUaSMu6jpadCDeaRT7tfhKD7sHTAh3nOe++9x5BgtrFJSsIwBNp+0AklHBvT3NRAy9eIV3xRIEVD3wvLVogxUTjH7Z0l/dBrZzuoV9+ot6ETZlMElaMkRQ0nAt5EDFDXjx50j5vAPElr3KNr166xtbWF2KmKC5F50cGw15bsZYGtPmgiY9Dx+mEQvBNs0kxx2SqIXhZqy9S3K0AHlUZsvnB6/Z8+C6tGK85pbXj73UjbJ85s1VRlxZtXO965tiIMKpAzrVR1rG0jO7uBpouIgbpIlEVi6APTCp7YCmzVASOJJquSSaYUJjF0wWQowWb+N/RDpOuU9vY44YWf27fj+vXra/fY49b9bs6Rt1vVE7ZPnaHMmZH3FRbYmitG17ZCM/gDsXRRW4+uExIwnwiTukD8FqumY7Vq2e8OtDQlO5Vao/zAUWV37H6n2B0wJB5hHd7Aw6Trk7Q+rKCbUuLy5cs899xzTKYzzpw7p80nYyjKCQaYVqqJ23fCsvPr5mZKSSX+snzgpBCsr6gmGzTtwHK5pBtG3p8qhwmqUOadV0eCoaNts2NwGjCcLAz2w17KAlKz0YsXL9IOd/uLpXyP3F7mqbukY96lC9SFYqCFE+4sNPnpotL7xqGV927sU9cVXQ+rVaRpI/uLSMyDD9NaOLMJe4vE5hQkwvVbkdJbnv9YhXeRvd1dmjYQ+gHvLDduRyaVJYmwNYlMS1U1G4bItIJZGcAammag6/TDdMHSRqf87uTU5icpDdSIMi26XhiGX4BG2niTXbx48YGPO+6GPmy9Yp3jnatXqadTnNNg652l6y2dVON9hqAYkzFqZBcjOKcndh8NG/MpGM/efkvbxazlq7Qfl78owsFpF1Gy9Wzy6GXj4VHRk0igh0eDF45bV69e5cyZM5Rlma+5Y3dvjxgUe9fvuRCisAqFsh2AFJUkb5wDo1zKSW1Z9JYhWmazOUVRsr+/YGcR1lhkytq8qnol1JXqdezsLRCJlNXPhtWdxAP08LLWcu3aNZ566inKsqQflIMruYGmqlvCznJMGvTeKF2PyfuUMtauxYWl9Bp4u35AcDTLQNcnrt+KVF64cUfhjJt3Is4IXSec3oDCwf4yUpVrH2jqqqYsa4hL3ru5Bwal91mLiYnFMrK/P4DoKLe32lBPWIwk2k64sxcxztANStwOKU/OCUoti4m+E9pe1voLJzrovvXWW5w/f/4uPdaj67gv7sF0mv5ssVjQdR3nzp7l1PYW2jizzGaFcmnHrDSltaVHTFrmxGhY5VHG3caBKyjKKe/tW7pmhaBdUW8UJ0zZvnuIFi8dURyz6tGD7uHPcRI73PDhZLqjx9Yzzzxz1xf62rVrPP30U2xvb2KcI1KwtVnrAIwcjBAPQXFe5wzeO0IyrHoNDnuNw/qC2WyDZSvs7OyrRkM2nnbWEEPAOkuyE7ZmjrYXbr/39n0FfX6R1+HK6/bt2zz77LOADpuEdfNMaz5rD9wh2jZl/DbS9sLNXX2U2qZLduTSpGi5ahFTceNWoKBHJPH2tYGnzhrevDqwOYPXrvSklFg1akJ6/rTy71+/0vHezYFpBcvGsLWputW7u3ukpDDREATvLV2vmXPXJcIQGaoZXXQYAqtOuHw14Nzo06bQ4hDUmTjGUetBM90QDiZkH8c9+9h5usMw8M477/Dcc8+973OPK0MPv+5PfvITLl68qFmvtcznNaSOs9tCDLphYYiklEcTc9Demitv11vYqIXdlcMZFSy2ruJWM6df3QGJGCP0fU9RFPRBx0kdAxGHc49+uY6emiep2TK+7w8j6L711ltcuHAB7/36dd98800+/vGP45zDO8fmtEZCz9Zc/fRSbqKCoekMKegM/nRaYDCUDiaFTqtZo8I3ZT2lkU329vaQqMwTSUo5CqlSuMEmXDlhVle8/PLL60bvB11rUZ8PeG0+KuvOnTucP3/+wGy01yQlz4xknvSBSPl7O9r5V9de1Ujo+qR6CBLpu8DtnYbV3g51qVNh3huWjfD0WTi9ZVmuIs9dcOzuR54+67h5J3Djlgqp7O0rRPDSs57ZTKur01uW3d3AdDphYz4DadnZbSm9IQTVZtjZ99nKvVcDWetpm562TdzcJY8qO9pWFQa7wdD16tvWtRrAu14PjhHifxxDL4890718+TLPPvvs+waZozfn0Sx3d3eXlBLb29vrx0zrCucdtWs5txWQ7EbbtllxLCpROmJZdhZndHLGWf09IQPohbf05jR3dlfs7+2zv7ekTXOGZJl6zXIrr531Ry2vT/p8Pvzs7IXxAH766afX16Lve27evHmXOHRVFRSFw9NybrNX1TJR/mfEM0ShbSK+UIGSWZXW3lpNlvoLEQTPKp3hzn5kf2+X3b0FwW7QRcfUt0QM3hnOnz/PL//yL/PWW2/x2muvPdBm6WE/80lZi8WCvu/vuq+aDhUVZ5ygBCFlrVnYX6m+AilROZiWQtMmppWsR4QHcdy8ueT69Z4ntoTNuWE6MbSt4rZVAZISWzODtYnTm5Zzpww/fks1p2NULd22j/z03R5LoiwMhVcs/+zZLaxJvPfeba69u8/2DHYXkeUysmiU5eS8wztD0yYWjc1NM2G10mZe22slnJKwWA7rBpo1UB6Jrx/m0MtjC7oiQtM03L59m6effvp9H3806N4vyz265lOVfzy3Ffn4mR7LwKq3IIkYEtOZKo2NCkhNbyi9qspXhUrHeQuFM9TTLZZDSRMr+iA4EyltT58800pHREMIj1SKPq5S5ee5ftZM98qVK+uMdrwWb7zxBs8+++w9Hf+tjQkJy7mtxMULHZNiYH+ZB1oQqspS+2y9Dew1GiRu7KmI0ZAVo5xVilqQOaveqd23CIXtGVJJ6XRgxnvPpz/9aTY3N3nllVe4devWQ32+k85Kef311zl37txd+9r0OdDKOMlnMMLaKKAb8lBEgMILm1NV+PJECpudfLFAgbWG23c6ShuoCmU17O0HvBVWjdqrhyCqny3wiWc9bS+88dOefkhsTgxPni1YNjqlGLqePKNLWZSImdD2kfduRV542nH9VuD0XOGQIRqK0tG0gcE42kEbqm1vWCxjFsfXqbrlYgAMGFEz2yNb+pGFF8Y13miXLl3ihRdeeKgv5eGb82iWe/v2bbz3bG5u3vO8zVlJNDq7XRWJj58LPHkqAFqabm96ZmVSkZssDVg6wVqdXPEu013U1IIYIpPpnBgGStmjjxZwnJp7iqLAe6+Y8QfMek+60DU8etCFA72NJ598cv1vbduys7PDk08+ec/z6tIjqIda4eGp0wMvPjXgGDAGTm+XOKdskxA0uG5OMh8zBwdnJY8IQ4w9s/lc5UTT7rpBtL2hEp1qKyWcOXOGz3zmM1y9epV/+7d/YxiGB36+kxx0d3Z2MMYwnU7vDrrd2IBUXHbdLDFqydMP4AgM2VrdGqHpE4JQlwrb9N3AQEHhDFVp6ftE3/ZIEvYWibeu9ngrXH6rxzt49+aAd8og2J4bfunpgjs7gbeudpAibSuUXiuYstBpxj4Ipes4s+WZTuDGjTucmgtPntHPEZJjNvN4m0g4hpidn6NhkelvagevdLSRLuq49zv+kYcXrLXs7u7SdR1nz579wM8/nOWKyH2z3HGVZUEQjy/UN+vpUz0vXeg4taXjns5qV9SAdj6dZrh3Fjq3P2rpDsOA8zoQMa0rpkVQfCtpaWOtpSgKyiz/90Gy3l+ETPc4YZSHWSKypohZeyAWdPnyZZ5//vn7Bq35pKBPTptmDjankU99vOWpU31uk0vusrMWXSk9vLdnmdeJwmngFYmA4L2nKGo2qkjTG4aY2Kj1dzvnKMtScWXv+eQnP8mZM2f4wQ9+wI0bN+77uU9y0N3a2uIzn/nMPYfpqhtplKDZn+KcGLh2R4XLuzYxBEPXR5pWm2m37mgjqvIBg6MPjrp22cdOuLMbuHptxelNnT587/bAx8473ni7Y3NmeO1yp42wTCV78qzniTMFISRObVgWywNXEHWeGFjsd0xKy6nNivl8ipV9YhxUl0M83lt27vQ452h7Qxg0ux7CmllKCHp/u1GRTu5NpkIIH1of5rFluvcb933Qc+7W09Xn3bx5k+l0ymw2u+9zt6eWIXmsy06/wHySeOlCw6xYMUTFavYbzYD6QTMjCyDjMAS0bUdRqrTfvFgiRkWtm7bjX//1X+l77SSo0lhJURQPnfX+IgTd43RXH+Y5Xdexs7PDuXPn1tdguVyyXC4feCif3igQCjAFzh3IMH78bODCfA+bPbdWncEZYdnqgVo4WZshOgtd21JXE1IyVK7DOoMrCoaQePnll1kul8Dd+yoinD59ml/5lV/h5s2b/OhHPzrW6eMkB11jdNjnMFafBFZZ+DuJZYhwe+ExBparxM0dDVjXb0X6IQ8NZceGthM2p4K1EesMxjrmdaIs1Ta9aRNlYdlbRJ4+Zzm9bemHxMVnCpo28vzHPMtV5K2rHRahH1RP9707A3uLAetgWhuaJrJaDfRdz2yutu5tMyAY5vMNNucqVtVneKmuVZGuDyqUY8mN94xaL5c9VQE+V05Jjk+kPqyhl8cSdMdG0dbW1kM/Z7yhx8xxDMJvvPEGzz///AOfO58UWGPpY433lunEUhY6ebJdrzg32SPGxM19HSEe9TaNUYEOg9D3A9Z5kljtXvqOTlR384lTmzz55JO8/PLLvPvuu+usYHSPeBis9//P8ML169fXGe3hLHdkotxvOadTZV0qMc4xqQyTWulhpYs8Od/l9HSPtk/rabXKaxXTdgZvBEkRkYTznhBho2joYwFi2ZxNefHFF/nRj37ElStX1p9tzHp1qs3y4osv8uSTT/LDH/6Qq1ev3tPw/UUaehn+P/bePLqu8rz3/7x7OpPmWbIsyzO2Ac9kICFD0+JAE0KmFpKShIxNAwGa9ndL710d0tVeerO62q4QCKRJk9XLIkMvt4Gk9EJbIG0G8IAdbMA2nmRLlmRrOsOe3/f3x3vORpJlW7Il2aZ812It4OicffZ+z3728z7P8/1+o1fnVwH6RxyG8jZRrDPBvmG9mxgr6vu1UIpQUtFWrwNuPl8im7bp7jCpqRH0DoQM9Bcp5l06mgQtjSaZtIHrS13/ReG6MVUZXV9trDVpbzY50ONRKEZYJrQ125iWQdrRtVjT0FrKBiUuW1ScFP4AACAASURBVGhgENN/MsIxJcPDIdU5E8s2CAOJbYVU12W1sWmk6/y+LxNLL5QiPxaQTetdrxAQh6fex7O5rrMedCsNtMWLF8/ofeMz3coJ9vf3U1NTM037FC2k7EavzgJLqamKlhGxsHaE1mpXj5Vpx49EzLFQUrhuEctJIyXUOkWi2ASl60AN1YKWlhY2bdrEyZMn2blzZ5L1GIZBKpXS2qNSEgTBlNngpe4YC+cWdH3fJwxD6uvrk/PP5/MEQUBDQ8NZ3++Y5fpvlCFGlOewRbI1bM65rGgZJmUE2g5cKcxyhjtagFKpQCqVRipIm75eGyEIpEFtRlBbW8vmzZuJooitW7dSKGgf8fFZrxD679atW0c+n2fnzp24rgvMHT9/PjDVKKAhKnY7msk5MGoggaJrYJqKkTzUV0liKUgZISeGYvxAN629QDKWD8hmHCzTpK0pTcnT42SmJXC9mFIxxBQSpSRH+0PG8hGFYsTgUIgfyGRSZcUiLbaw/4jH6FhI2oGRsQjbEjiOID/m4ocpHCMgZQakHcXOlwpagtLU5qZS6Cw+FNotHKHLHGEoy/ZOimIpIg5jqjMCx9a7JMucmhk7W5j1Od3e3l4cxzkjEeJ0iOM4yYaklBw6dGjawbuhxiKW2oLHjZyEuqiUUa75Sbrqi7RX58uTDWXWCVDyIvIlB9+DohdhEhALE837t6jL6mPYts2aNWvo7Oxk+/btE7Ke8TXBqbLeyTzuSynTrXzvcxkZGxgYSMoKlc/Zv38/y5Ytm9b72+otothECaGFaiTlNExoiU4DHEvSUlWgKVtIbighQMmY0Ty4vsnJUSD2iYUNShBEFg1lRrphGCxbtozLLruMPXv2cODAgeQ8TdNMGqhCCJYsWUJXVxcvvPACPT09rwnSy/h1tcwKsUFnhmGkiQRjrigHZIWKQmxL4XoxBVchlHZZzhcCRktpLW4eKdKOQW1NijDUbE4hBCVP0tPr0dfv09ZoEkuJjBW2JRgeCeg/oRuXJ0dCanIGSxak8ANFvhBTndN/7/sKGbs01Dk01hm0NmgX5/YmB9tUFH0bNzCQmIBBdV0VgRS6kacUYRgjlSZGBJ4k5QiqspKMDbVZRW1ubidpZ/XTK2yjXC53Tk+G8Td0X18fTU1N0w7eTVWCUJaVo7AoBpXAq29Aszyfa4qYRQ2jpI0SUmn2jOuFGFaKvCuoS/lloRRBFBsYVGip447V1MTmzZsZHR1lx44dSdZTyY6mynr/K5YXKmSDSgkGXu2YT7f0lHYEkRIoCVKZjIUZIlUWqS9vEXUdTlGT8lhQO0rK0A0Xz/NIpTLauknFZFMxQkAgtSvJZI2b6urqxM1169at5PN5gKSBWsl6q6qqWLduHb7v88ILLyQP2EuN9FLBBFlVQTLH7vnjDT4rLC4YGPBJOzA4XHZkDiQj+QhblGhtMJISgOdGtLY4LOzIkHEUhoqpykJHq01rk40fSBprTWqrDdI2tDc55DKCwaGAlANHen1KXkxLg0nK0SQIwzDoH8hTdG0KxRjHguYGA8cR1NeA70c4KYtIGThpCykNMKyySJLE90NcNyZWUCwEBEFELiNoqBGkU5LmWskbr5xo2TTbdftZDbpHjx5lwYIFmGWb9OlCKUVTUxP79+9naGgIKSVHjhxJaInTgVHWV/UjrZUrhUUpShFJUZapU+WbE1DQXO2yqH4YGQcoTKLYxBQx9Tm3rCUKpcgh5UwdZCod7u7ubnbu3MnRo0enzHrjOE4abZfqNrSCmQTdysjg0qVLOX78OL29vUgpzzqJMhUytqG1W6XW0/BkCi+2tZBNWR9Ae9gpHDOmo3aEKrtEGEsM0yaMobGqgDC1RqwbOklgmQzDMFiyZAmrV6/mpZdeYv/+/VNmvQCLFi2iq6uLfD7PoUOHEibjdPH9738fIcRuIYQUQmw6+zvmBpPXtWKg4fpURmJRSs+9mqaBG0EuLTCRNFX7HDwWcnLYx7Ed7eyAIm1r+rXAIJ2zOTkcMDgUUCzGBJ6e6cukYHisXFZAEUYxmTS0NGjn544Wm5HRkL5+XTrSRAZJJh2zsCNDbbWJaUIQlpunXsyS7iyWpZ0nbCdFbGrLoUjqXo7vKSJZruXmA8IwJpcxaGmwqM4IFrYqanJyCqPO2Qu8sxp0u7q66OrqmvFoUYVptmHDBo4cOcK2bdtoaWmZcWDKpTTNr1LLVcIkH2Qo+g6x1B4QtiExTS37aImYy1qHaa8LcayAy1qHsEwDBRQDG6kMcmf5Cg0NDWzevJliscj27dsplfQA4PiaIDCh3HApb0Onu64nTpwgnU7T2NjIxo0bGR0dZevWrZimSXV19YyOW5PV1F6pKoaSglDZjAVpvNDGD7UNk2WqMvdf0VqdZ3FLTBhLmnN56jMRAkEpsFBKkD7LRqOqqopNmzZhWRbPPfcco6OjyTWojA0KIUin09TX16OU4pFHHpnRul5++eUA7+cC+9pNXldbV9YoeeUyDeWpn0joKRLLpiodU1PlIGRIFCksPGzLAqk41h9xYjgkjCQQ4/uK1uYUjQ0WddUmlgVDwwH7DrkIqQgCydE+H8+PGTgRUnJjMmnty9bZ5lBdZdI/GGKb4Ac+qZTD6Jik97iPZepE6mifh+vF1NTq+zbGwrBMlJVBIYhCRRRCqRQhhKFpv6EEKanJCTqaDRprTFYvqjiMx3NG6571mm5lDnMmGVHlKZJKpbjiiitwXZeBgQFGRkZmdPzGrBZDCWKjrIGriJTAVw5DXo4RL40bWvihzpzGXM1SaaoOuHLBsFYikyZukCoHb2itO3vGbpomK1euZOnSpezatYsjR46ckvW6rotlWYRhSBAEl2x5YTo7GKUU+/fvT+rxtm2zatUqoiiiWCzS398/o+O215Y90eKKxKPOvGJMSlGKYpRl1M9ysuhQCG3cwMQNoCYTs6b9BAvqioRYZbt1LYZelzv771MIQXd3N5dffjn79u1j7969ycOzEnw9z8NxHBYsWMDixYvZvn073//+96d1XqtWrUIp9fKMLsYsY3wPpQLL1IG26Jb/R7lMF8eCKIqJYklh1CflCILAoioToWTMywc9PD9iyQILxxbkUoKxgiYeGaZBFEj6Bz2ODwSkUgbLulLkcpr8srQrhYwVzQ0mo3nJ8EiE78UMDgXkMibtLTYlT+K6AVVVGRwbanKa1ptOl8kXflS2DzIwHFvrbBsWUSgxDBgbCzBMrbc9OlxOjkxQ0UmaaiULWgW5rE0qlUp2LWEYXtzlhQpmEnQrivWVk+rp6aG7u5u1a9eyf/9+9u3bN+1SRVNNWR1eWoSxPjUT/SQMIgMlbAzbBsPGsm1M20QYehwlxCEUKWIsvFhLASqg7vTjwaegrq6OzZs34/v+hPlPINEXEEIwNjZ2SapaTXddjx8/Tm1tLel0OlnXwcFB6urquOqqq+jv7+eFF144K9urArv8fIqlgReZVAS0TUMrRAkhyg7DDo5tkskKqrIWlgUxNqU4h1QOQaw/KI6hvW76WUwul2Pjxo2k02mee+65pFZtGAa9vb0Jjbmrq4v169fz7ne/e9qffTFgqvKCtk4q3wV6N66ptaHUDgu+ZpIJIqpSLqHMgFKUCmNEYUgUSi1qs7iKptZqSq7CcQzqai0WtDlUVxmM5SN8T5FJCYZHIupqLIJQ0tVmkXYEuawuZxw+6hFFkHZisllt3Z7NmtiWJJcxyKRNOlosgkDS0poljBRRKCm5UXliQX9/L1CgJIWRIr6v77+UbXLF8gy7du6g2j6ZXIejR48mu/YoipIZ/dnAnDHSppsRTR6lOn78OJ2dnWSzWTZu3Iht2xOaGmc+LnqoSEExsLQ9t6GN6wS6pBBLzbBJ2VqgI4w12ymI9c0cRPqSlE0kZgzTNFm+fPmE+c++vj6ay0Ldtm3zi1/8YsZZ/MWA6ZQXxguUV7Ko8fPWtm1z5ZVX0tTUxNatW6etceCYAIpIWvihfiCaQg+/K0VZE1lnY2FkcLJgU/Qt/EgbLMZSN01luQY8WdDkbBBC0NXVxdq1azlw4AAvvfQSQ0ND2LZNLpfDtm22b99OoVCYINT/rne9i8svv/yUf/7pn/5pZl9gDjFl0JUQBnFZf0EHXt2SMLTLSgRChvi+iylsqrOCxR0WRc/haF8BoXyslENbZw0di2rp7KrFMLTjx8hoxPF+nziWOJbilcMujgWHjrqoGHr6AtKOoFSKaagxaW9xiGLJaN7DNNNUV+l7u7bGAhS5nIlpQPfCFLZjA1qk3PV1LAgjhe9FqDgmDnzyY66ecAFsW7B4YSObNm2ilD/Brl27KBQK5PP55J49cuTIhATqfDEne9zpZkSTRW0OHz6cPF0q/7+7u5umpib27NlDc3NzcjOfDhkbRkq6FjVctKlOhwmbSUmQAiJlgJQUA5u0IxkpGtqOPRIVpjlhJKg6D1GhyvzngQMHOHDgAOvWrQN0PfdnP/sZP/3pT8/9wy8QplNeOHr0KE1NTRNqm8ePH6e+vp50+tWucFtbG3V1dbz44osMDg6yfPnyM3b+azOKkZKBZSkKnknaglxaapovenYXtN12EJez3AjSjsINBHqBtd27bZ77VjGTybBhwwaOHTvGzp07k6agEILvfve7/N3f/d2Ev3/yySfP+VjzhclJkmXoGdYwUqTLrK3A044NwignNbGBXXC1j53StlmuF1MsKZrqUkRhiaWrW4hCieMI6lqrOXZ4CMtQpByD2hoHiSAMYfHCNEopWpu0nkZVzsANJG95SxM/+/kwlgGlokcua1GVsymWIpSC+loT01CkMxa5KgcMgbBtfF8gsfDDcvlASlxPURwtEYcRlmGjVVoVpmGQsnUJ7PLLL+fEiRNs27ZtAlPyvvvu42/+5m9m73rP2icxM93VyVmu7/ucOHGC9vb2U/620tSI45ht27Ylzaqp0FIt8aOK35lB3rPx/IrPvc50/RCG8gaGaRFEJlKZIEy8yMQPDIJQ4IUG9bnzc0kwDIP6+noaGhrYv38/r7zyCt///vfZsmXLjJtJFxLTXdc4jpOpk/G1wsOHD9Pd3X3K36fTadatW0dVVRXPPffcGbP/7mZJKDVjSghBKbIZcw3cUCRZbCwFec/Esi0Uek7TL9dx/VDgheD5JlWp81tXIQSNjY1ks1lOnjzJnj17eO6558jlcqxcufK8PvtCYPK6mqYmELzqSSfp6w8YGAwRQmDbJmFkMnhijHTKIQwVyAhDKJZ3WQihCFQ1lm0TBBGuG+LYJk7WKTu4SIpFyciI1s/1A8ngUIRtQaEYU1ttsXJlDW1tKd5wVS2mJfCCCM938EOtSJ/L2WTSJvkwrUXpMRDCQhgmUgmslINlW6Rsg2xa+6FpAXuBbQNKag0foQV0Kqivr08Shueff56jR4/y7LPP8p73vGfWrvcFKy9MznIPHjxId1kQ5XSfuWzZMpYvX86uXbvo6emZMgB0NWmfpjDSMm0KAzeyGfUsRkomo65FMTARphYoDyMT09ZjZTEWnrTxIgsUdNafvzXN4cOHWbZsGZs2beLQoUP80R/9Ee985zvP+3MvBM5WXjh8+DAdHR0TpBt7e3uTbdpUEELQ2dnJlVdeyf79+yeMaI1HxgFTCIJQP0AF4EcWbpRizE9TilP4kYlpWUkAzmSMhCDjxzZhbAGCpurzr6cfOXKE7u5u1q1bh23b3HLLLVx99dUzarg88sgjCCGOAm8CfiSE+Jfz/mLngFPKC4bWLlaxNgd1SxGqTJ+PY4lhaGJEHAuItUTj0HBEGMZaOlMqFnRVI4RJKmVpEXoZ09JRq611ChGFUkh1zsAyIF+IaGqwGB7Rgbf3uM/CrhxSQl2dw8ioS12NRXW1SSZlYKCde+M4piCqiaWBaVvUNlWhMAiVDcIgDCGKFG0tNumUQRT4+jxVhWGme0nOuIGTvr4+WltbWbNmDQsXLuT9738/q1atmlWz0QvSSJuc5bquy9jYGK2trWf97Mq2vVgssmPHDm0wOA6GoWc2vVAP1At0FgTaKTguM9QQhqY7GgZ+YOIGRsJ2kmVOdt15JqMVSmlVVVVCF163bh0vvvji+X3wBcKZygthGNLb25s0C0Fnvj09PdOat67U8C3LOm0N3xSKWBpEZVuYKNbbYBQJgcW29FiZYZmUXL1jkcooK1NBLCVdjed8CZJzHRoaoqWlJSFLNDY2UiqVZjRmdOONN6KU6lRKpZRSrUqpa8/vm50bTikvmFqfQJOHFK4bEUtt1lpytVBMFEpiadPTWyKXlgwMhTgWDI1EZNJQVZMiVoLB4RhfpimVJKZtIFVEc4NDW4tTzmAVjfU2KKiuMqnKmbS2pshmLZRSmKYgk7EwjBQjo4pCSQIGpmXgOBYRaYJIz81na9KJCamMJVJpdwgDRVe7Q8qIyY8UkFFQ/t0ooihK6vtKKY4ePcrChQsBqKmpQUpJV1fXrNZ0L0jQnZzlHjhwgMWLF087SzBNk8suu4xFixaxY8cO+vr6JhwvbSoEAjc0EkaNECrRXzXK4rl+ZGCYmjMaRFpFUyoQszSfd/jw4STgKKX46le/yh//8R9z1113zcrnzzfOtK4HDx6kq6trQpbb09OTWPNM9/O7u7tZvXo1L7744gQRGoDGrDYeLPkGquzcLMo6r0KAaZnaDDHWnPtYirLlNsmUA/Gr0xDnisnuF/fffz+33347X/7yly85wZvxzc4KTEOrgkmpkLGiWAjLduXaKTft6N1GyTfxPMmRniKZtGDXS0XiOEZKEzudJo5icrVVGKaJFA52KgVEjI3lOTkc0HPUIwi1lOMrR/QD61CPR0NjBt/XGrdSKhYvzmLbBm0tNqYQpFJanSwWFghtNimVwkylieKKyaQWPQ9CWVacgxuvbQCpGD1RYHRgmJHBUWoyryZ/J0+epKamJtmV/eM//iPXX38999xzz2ldzM8F8x50J2e5xWIR13XPSXe3sbExEaH55S9/mYx1NFbrelQkBZ6vkmzXMrUtNBX7HtuiWCqPkgiB71PemkKVc36lBd/3KRQKiajLK6+8wsjICJs3bz6vz71QmOrmrMDzPE6cOEFra+sEHYK+vr4ka5gJKjX8KIom1PC7mmLiSGtq5N2yYaXUW+A4kmX5Tm3TUihI/BCUMCgUy64HsSbGnA+klIlzLujf7+OPP87NN998Xp97ITHV9ILn6XsmiiX5QkAU6WtomVoisabaQpgGuaxBVc6gJi1padDkiJGSgWFZhNImCiMqfh9g0LqghbGCwC2WaGm2aK63UQqWdWWxbUFrk0N9Y5ooUuV/JHX1OfoGAgJfUfT0zG0QKkxblwj9yCCVtjBM3csJY4Hna+GcIFAUSloAacvbm7hqXRVS6fs9l4Z3rH+1eTs+SZJS8sADD3D77bfP+vWe95rumcwmzwWVrmNFenFwcJClrZIgKNejQlN7PsWSOJb4obaSNm0tYBJEBgVXUPIUpcDADxXFkqKl9vyCbk9PDwsXLkzO67777uP222+/5DKh8Tjduk4lUH748GE6OzvPWYtgcg3/6NGjNNfquqKSkijWIixBqAiCmOExxXBeN8/CUBFGBkFk4PkKLzbwQxgrQUPu/Oq5/f39NDU1Jdn7Qw89xIc+9KFzEni6WHD6TFfieTFh2bwxjiWGiBGGps1WZaG62iCb0RS21gYD04TupXUMnyjieRF+ySc/6lEsBuSLiqraLI0NWWprsrilIn39eQZOhESx4mifj20LslX6WkaRxLIgnbHpbE9R8rXoTb4YE0Zg24ZWC1O2pvYKizDSOsBBoANuEOrdUIXa/Nsf1dZhjg3vf1cNNVX6hXw+j2maiW73f/7nf7JkyZJzShrOhnnNdCdnuWNjY0RRRH19/Xkfs6WlhY0bN3Ls2DGOHtqDIbSSGCi80GA4bzA0qhhzbQzTJI4Uo2MxYdnEUJRFbvxAa24ubjn3jCiOYwYHBxMbmuHhYX7605/yvve977zP80JiqnUtlUqMjY3R1NSUrGsQBAwMDEzLG+9sqNTwC4UCzz//PCkzIijbWSllUPAMRooCN7SIpB7e93xJqLRCVsWiKYp0jb+j/tzXVSmVPExBr/O3v/1tfvu3f/u8z/NCYqqari4t6OupynVzJSXFfEmvs4CmhhRRJMiVlVdLpYhcWuBUVYESRIF2+A1CgTBtXfqJDAwTqqpSNDTUYtmCXKZEFIU0NzgUijGGaeB6EteNtRWTpV170ykDxxZYpkFjnYVplWv1mNTV63puRQtYSoUfagNKwzASucZM2uAzH2njnv+vi5VL09TX6odnZVwV9Drfe++93HnnnXNzvefiQ6e6ObXD56sC5aCz3OlK/E0HjuOwdu1a6urqCIpDeL5MtsVRJBHCKBvR6YZArHQmZDk2cdkANoq19UvNDJhok9Hb20tbW1vS8fz7v/97Pv7xj1+S1N/xmGpd9+3bd4pA+aFDh6Y0mzxXVGr4XV1d+IXesoW2SqQGhRBlCy+d2QSRnts1bLM8YqbtXRCKJafasU0bw8PDZLPZZN74iSeeYNOmTTQ3N8/KeV4oTF5X21SYAoIgxrF0hgtQGCtRKkQEfogXCUxT0NjokM+HpGwYHg0p+gqEQRzFBIGkqiqFQlAqaU+1quoUlimQqqxlG9tks9UMnnSR0qOqJoUQureSD9KMFgSmgOGCFqzaf6hIGGo7n5JH4vxsZfSsr+9D5AdEsW72aflkoY3zyvjVtzTQ3pKis82hpsrA8zxKpVKS/L3yyiuMjo7OWSlwTuZ0T7cNHU/3HR4exjCMKc0mz/c7dHR00N6cI4xifC/U+rllaToDhVKSsaK2D4mlwPdl+UYFFKSMc9+CKqU4duwYnZ2dgO50P/zww3zyk5+cpTO8cJg8MjY2NkYQBBMEyj3PY2hoaMp56/NFY2Mj61Y2EUtJqRiiUJiGwDQ0fz+WUCwpvEDXHX1fEoQiUcmykZzPc2ByY/Tee+/ljjvumKWzu3CYqqZrW7pskyoHXYFibMQDBKVCyGhB399RBNW1KfYeKFBbJRh1LfLDBQquBCtDFMQEoc6agxAiJbAdG8sySKcsmhpTGIZBU1MVg0MxwlQUSzElTyGFSUgKqWDl0iqkgoUdGWpqTE3cyGhnkSBUCNNCSoEfKgpFTZ7IF7SFjxAKt3iq1ZIQgkzanPdS4LxkupUsd3wz5lwk/maCy7oMTMPA9cHzNE9cP7EVJVcBr46OgS7ah6FCxpLa7LnXcysaA5UB60ceeYRf/dVfnfWHy4XA5JGxinRj5TUgofvO1Q/2soUWhiGIpEF+zNP+dkILbBeLMZE0UEIQhiIRqg+8mFgqnNPIOU4HxWIRKWVCannhhRdIpVKsWrVqls7swuHU8oIiZetaaDqlZ12REXFMsnPwfUnohwyPRpgGrFlRRRAqurrrKJZ0olMseLi+ntsVhp4iiUKBNByiWDEyppW+xoqSqoxFW3OW5tZqQOKGWvPYC3RTL1IGxZJ+aJ4cCst12kq/QGCaJgqBH+j7PAx0aUKPt8Wv+g9NQhRFSRMYdDL4s5/9jBtuuGHurvdcfOhUQXf8f588eZJ0Oj2rYxiTsahZEIYxBoJ8UeC7AVEU47kSL6AchEEYJmGon8KFYkzJk3S3nvvNeeTIkaQ2JKXk61//+px0QC8Exq/r0NAQhmFQXV2dBNhSqZRw1ucKpglGmU3k+oLRsYBi0aNQjImVheMYhIHCtC1cTxJGioIHxWJER9O5P0zH1/wAvvrVr3LnnXde0o3RCk4lRygyKd1Qy6UqDy6/bJWkQAlsy8ALtcB4oaQQpkFtjYWVzmCZJsrUso8qivE9H68UEEeSGMhUp3Bsi8Z6m0xWC5QPj+lmmrBSSGVgp9KYJliWIJICJ2WRTQteOeyScvQcrlv2OpPCJAjBD2LiSHu2eW5IeRSX/uPFpJE2Gb29vbS3t89rKXDOphcqizi+eVZZ3Iop4VxCCC2S4vuauhhKh5JvUPQllCuAkRSEXojvR8hYJXOBKzvP7bKMjo5i2zbZrPb3+fnPf05nZ+eUFNhLEZV1rQiUVwxDx89bn88kynTRkFP4XohAEEsTL3S0nJ8pwDCJYigVA60uJfVYmYxhdde5PUyDIEiahaC1JF566SV+5Vd+ZTZP64JhctA1hKIqo0WBdG9Db8+lVIRByPDgKHEY4ocWvh8TBDEHezwUZnlXC5HrEcbghRBJg6g84xuHCmFpAfqSr/BcSco2yKQMchkDxzEplMB2bIRhItBJUl2tQxRJlnendQAVgqqMgWUZKEML1QcByCgmjHSJQiqIwwjPi7GtU3+TSil6e3uThm+lFHjrrbfO6fWes0w3sXSeJN04MDAwA7PJ80NrbYTnxxhCi6EoDBBak1Vb9NgEgSSKICrH4rSpSRTngvE1P2BOO6DzjfFaCoODg2SzWbLZbLKuhUIB3/enZTZ5vuhu1Z1tw9AOtVFl8YBS3kUYBlEoiaQiljqYmIaiqfbcfu49PT10dnYm5/rAAw/w2c9+dlapoRcKk+evlVKYhqShWuA4iqwtdTmhpN1P3EIJ01CU8h5F3+BYn0d11qCt2cGLTUrF8o7Si/TYZhQSeCGBH+P5Ma4f6wdloEilDLJZG9s2GB7V5pSK8rSBbelmmasF7MeKuoxxYjggCCSZlK7fBpF+PVa6thuGiiiIdUkEGDpRJI7VlJnuwMDABK2F+SoFzvqvZvwiTnb3rUj8VcSt5xr1Tr8eXQmlpi3GZb6o0MaEURAkoscy1gZ5Nec4x+m6Lr7vU1dXB+ja5uDgIG9605tm85QuKCpBd7xAeWVt9+/fPy9ZLsCCmpMgFJ4XJ02eONJbSz8UBJ5PFOvOdVRmPOXOkewSxzEDAwNJY7BUKvHYY4/x0Y9+dDZP6YJi/JpJKbEMRXujIOsIaux+0raiOqunQzIplfj3WKagpdFmz96SJqeYKZ3NBprBFvuew0zbIAAAIABJREFUDr5+SOiHRH6oa61KkM2YpFMWrh8jJbS3pkinTcLYRDhpfD+iFNjEwkEYJum0xZGeMTw3oORGvLivgGEIPf4pRWIrFEaKYqGsfRtHFAohUjJlpjtVKfCLX/zinF/vOZV2rGS5lYygr6+PxsbGeRkkj+MYMziCMNrw/FgPWact4lDilxSWbeIWApSSYNp4foxpKBY0nNsWdPwCgu6A3nbbba+Jml8FQghc16W+vp5UKpWc2+joKEqp5IEzl9CzsofI2OtwQ3BLEZmMnrv2XLAckzCQKKHnQd1ihCEkDc3ntg7Hjx+npaUlIXk8/PDDfOADH5ggU/laQeWezaQEGUdw+VIDU/bT0bycpuosP91Roq3R4sBhD2QEhsGJYkR3Z4refp8Fy5sIYwj9GIE2p1zeabBqqUNtlcmJkYhde2NGfKhOmXhujONYGChKpRArZSBMC9N2GB3JE0kTx9GUX8Mw6ezIUSwWCYKIFUuqMS0Dqczy2JgeBVVRRBgpTFuRHyoiKOsn2xPXf2RkhFQqley4K6XAmfgynivmJOhWuqHjiRAVs8mNGzfOxSFPwdGjR+ns7CB9NGRMmngehH6AMDUnPyO0UpGUAkVEFMUIFBtXzvySVARQVqxYAegg9Mwzz/DXf/3Xs31aFxzFYpF169ZNmMt95ZVXWL58+bwc/+TJk+RyORqqFIcHJUpqPyupFEIYGGaZFCMUYaCNB5VSXL5k5utaIUNs2LAB0L/hb33rW/z4xz+e7dO6KFApCbbWa2W2RfVHaWrs5r2NOWxDTxu0NJpUZ+H5X45hGZIgNBHELO3KUAglUsXIOKa7TXDbRxtJORM309deDf/y0wLbX7SxLRBIisWYVApiW8tEOkoRSRPLUFqDQWiL9TA2yOWqsAOf/v4RLncWJboaUmqh9UIhQCiJCn18L8JyNM047UwMupPlRu+9915+7/d+b86vMcxhpjuZ7nvs2LFzMps8F8RxTG9vL1dddRXtDSHDPVqZCAFxJImkIA4kQajrvKapK4IqKuEVI2pyLTM63mQBlG9/+9vccsstlzwZYjKOHz8+wWwT9BSDZVnzog9cKU+tWbOGvDQ40BshTAuFnj4xDW0lE0ltJyFjLXwkI49UPIBSC2e085gsgPLkk0+ydu3aaanhXYqoJEm2JXBdj1JxlNbVK2hr0yIyd97aSv9gQGtzI8cHQ3pPKL776CC+N0bRk0ROhFI+i9pMvnTr6Vko1765itExONInKRRicjmTY715Fq1oQClFcaSI5ytSNliWHllLmdqdeKjgY1qCdLaGvGuQzurkSQgB5YAvVERxLMS0rMSUIDVOWdR1XcIwpLa2FtAN4PksBc5ZI60ylws6CFY8h+YDFUaYaZqsW24S+hFKabUhgR6JGR4LtB27MIiCUOvntqQ4fvz4jPy7JgughGHIQw89xKc+9am5O8ELgCiKOHbsWFJWmK956/EYHh4mk8loGcjVJkpqN9c40ttH2xKMjIZla3YDL9D1+aZaiyDw2L59+ylSoGfCZDLE1772tddMY3QyJvdfJiv/maZByjHoWpAm5ZgsWpCmvdmmc0GW9rYqqqscbFuQceDOj59dO7O9w8FxLDKOTdGNSTsRkTQJQoUf6NLEyEjAyaFIz2XHsKi7mq6FGWprHMjU6WmkksIPYwwBhhDIMMLNF8vnAyg9b5wal+lOHv+rqMTNVylwToJuJpNhbGwsERrv6emho6NjXjI/KeUETcyViyy9TXHDco1ZEoeBlv4LI0Ss5wcDP2T5ArjiiitobGyctn/XZAGURx99lHe84x3zUt+cTxw6dIgFCxZgmmZiFnrixAlyuVwiEjLXqAjdA9imQU0mxnMDojBAxRGlYoBh2RTHXIh8DCSe69PZKFmxYgWLFy9mx44d9Pb2nlX3Np/PYxhGcm579uxBCFGxTX9NoVKP3717N2EYUiwWKZVKZ1X+a28yy6QHg1jYqDjmHZsdcpmz72ZrcxaptIPtgJIeocwiLBMMi0JR4nkRTiaFZZt4XkSMwMnYVNdlWL6mjbVX1JdNI/U4oAKiKGb4RF4HWl7lBtimIGXpfw/DkJGRkWSWfHR0lJ/85Ce8//3vP7+LOAPMetBVSmFZFhs3bsR1XXbs2DGBFjvX6O3tpaWlJQmCQghqMiFxJHHdiHw+xA8NDMMglAauF2lNzzDijVfqLK69vZ3169dz+PBhXnrppdM6904WQFFKcd99981LB3S+EQQBnZ2drFu3jlQqxdatW9m3b9+8TaKMjIxg2/YEQk17Pcm6FooxkTK0zoJUFAph2bk25k1X6qZXQ0MDmzdvZmRkhF27dp3R4fV043+vpcYovMoWXbFiBa2trWzdupUXX3xxWpMoKUegAh8pBCVPoiKPG941PYX4XBYsRxDFWn61pSlNGNtgGJiGwAsMMCyEksRSs9PsdJpsdTVSaI+zINRMNNs2sCxBqeDj+RFeIMvzwxEyDGip9rHLQffo0aMXvBQ460G3Usu1LIuVK1diWRZxHCe21XOJSpY7uYyxZrFNHOuGSqyE9s8KfYSMiQJNjKjOKDKpVy98Op1m/fr1iX/X6OjoKcebLIDy7LPP0tbWlpAGXktYuXIlQggMw2DRokU0NzcThiEnT548a9Y4G5hq1PBtG1PEUYyUmuoplCT2SoiyDKGMFWlLsaD11czLsixWr15NR0cH27ZtY2Bg4JRjTRZAGRgY4IUXXuDXfu3X5vYkLxAqZYXW1laWL19OPp9naGhoWo7embQg8iPCQLJ5TWbas8t1OYHAwPM9spk0rq+/Q3GkRBgqLCdFYSSvab0V4RrTBsOk5EGhXCWKIm2gaVuCjmaLP/liE29cPcbyhQFXLjW4arXB2pUpMind3D9+/PgFLwXOatDt7e3l7rvvTupmQRBQKpXYvHkzPT09vPzyy9NayHNFf38/jY2NpzTr3r45gwwjTBETBhGBW8LzFVHgEwYxyIjFHadeivH+XXv37j3Fv2tyNlShhp4Jt956Ky0tLafdpiqluP3221m2bBlXXnkl27dvn8klmBP4vs9dd92VlFuklPT397N582bGxsbYtWvXtGvg54KxsTGEEKc06xa2OzhmjKFilJLIwMf39XoqqYjDgPbTJF7Nzc1s3LiR48ePJ9vqCiYLoDz44IN85jOfOWNAuRTXFeAP/uAPOHDgQHKuPT09rF+/HtM0z2oCC1CVs4ikIoolH3z39I0IanOgBEgZkKtKk8s6BEFEFMZ4bog3NpqsoRYmV0i0511NDjLlqVM/1OSm0AsJAsnyJY184ZNrecMVkpbaQTpaDNoaLTJpg+PHj9Pc3JyM/z366KO8853vTBpqU2Eu1nVWg25bWxtdXV28+93vZs+ePezdu5dFixaRyWRYt24dmUyGrVu3Jt5hswml1ClBsIJs2qS5FopjHrHvEQYRcRDiuyFRFFPMe1z75tMz5LLZLJs2bUr8uwqFwikCKEeOHKGvr4+rr776jN/z4x//OI8//vhpX//nf/5n9u3bx759+3jggQcuCq3WVCrFO9/5Tt7znvfw9NNPc+jQIZqamshms6xevZr29na2bt3K0NDQnBy/0tSZCssWGHhuSFDycd0QGUtKxYgoiHCLIW/bePp5WsdxuOKKK2hoaEi+/2QBFNd1+eEPf8hv/dZvnfE7XorrCvCBD3yAW265hYceeoj+/n4Mw6Curo7FixezYsUKdu3aRV9f32nf39JogTJorDWpqZn+ZJJlCgKvSLaqGqWgFOmJkyiMMSyLIIiJo1iTXRLxGu0MMVaAkTHNPisWY8JQkR+LEIbAsQSOY/Pud63imjctICwdAjmMbTGh11MpBZ5NF2Uu1nVWg65hGNx555088MADfOpTn+JTn/oULS16/EoIQVdXF6tWrWL37t0cPXp0VrelFUrf6Vxn163ULrFKKVw3xi0FuJ62eWmqhZaGqd9XQcW/a9WqVezZs4fdu3dPUJW/7777+MIXvnDWOtg111xzRqrsP/3TP3HLLbcghOCNb3wjIyMjZ/zRzxc++MEP8thjj/EXf/EXvPe9753QZGlpaWH9+vUcPHjwtG6+54p8Po+U8rTZyHVvz5bdZqFYkkSB1m31g4jqLFyx4sx08/E1/EOHDrFjxw5aW1uTrPZ73/seN9xww1lp65fqur7pTW/iqaee4l//9V/ZsmXLhHuytrY2scN64YUXiKLolPcvaHUIYnjnm2dGnQ3DkNAvkkmlMAwt96gQuL4i9H092hkpLOVz1UporFJEERzui7FMyWihLMsaSBACL4ixxkUzIQRLult496+uIwrG2LZtG+l0OiFmTbcUOBfrOifTC+vXr2fDhg20trZyyy23TMiAqqur2bRpE/l8/qzNjOlCKZUIZ58OW95ag6ECZBhjEiMjhaEiiH3evH76DLnq6mquvPJKXNflyJEjiXPCv/3bv/GhD33ovM/l2LFjE4J5Z2cnx44dO+/PnQ10dXXxvve9j6VLl/KhD32IgwcPJq+l02k2bNgw7W3pdHE22viCljQNVQqhQmwRUShKROwj4oC1y6f/806n06xbtw7Xdenv72d0dBQpJX/3d3/H7/zO75z3eVzM61pXV8cnPvEJmpqa+PznP89zzz2XvGZZFpdffnky0TMyMjLhvV0dNleuSHHdO2bmcdjT00N9dUabh0aSQlFThA0kbtEjjiVZM+TuT9Zwwzty/OY7LWIlWNppMjymqK95VVoANN17Ks2UdNph44Y1xHFMPp9PavjTKQVOB+eyrnOm2PGHf/iH/Mu//As33XQT1113HT/5yU+S10zTZNWqVbS3t7Nt27bz3pYODg5SU1NzRmqmbZtcscymVArwXF0DDKMY4pjrrpmZXVBvby9Lly5l2bJlPPfcc9x999185CMfmRXix1TZ/8XUMb/pppv4v//3/3LPPfdw88038/DDDyffWQgxYVs6ndGsM0FTPoOz2jld97YcbjEgCGKECvG9EBlJPrRlZuI7g4ODtLa2snbtWl5++WX+8A//MPmdni8u9nV94xvfyCOPPML3vvc97r77br7yla9MmNppb29n7dq17Nu3jwMHDiTnU1djs3xxdkbHiqJIj1o25BAGGKZBGJuEnk8YakPJrBVw92caqM7pe6q22iSXkoyMxTTVghuAYynt3K0UYRifVr6xUCjgOA6bN2+mr6+Pe+65h+PHj5+1FDgdnMu6zlnQXbp0KYZh8OEPf5hHH32UP//zP+dP/uRPJjQsxm9LK7OfM0Uly52OfOInPthC2oqRkU8ceKjQ55pNmRn9+OM4pr+/n/b2durq6rjyyit5+umn+elPfzor5ZLOzk56enqS/z569GjSbb0Y0N7eTi6X4y1veQtPPfUU/+///T8+85nPMDY2lvxNZVs6PDw8I6LJZExXHOmtm+torQdkCHEIMuINl9uk0zMbA6roZ2SzWTZs2MAvfvELdu3aRbFYPKfvPx4X+7rW1NTQ0tLCihUr+Pd//3cKhQI33HADvb29yd9kMhk2btyIUopt27bhui4Am9fNrLRQGduqrjKJwwjTEBiGoFgIcIseFiF33NJANjNx/aqzCscxiCKJYwmCUJsSKBmjJFjG1PfxkSNHWLRoEY7jcOWVV7Jnzx6OHTvGoUOHZvS9p8K5rOu8aNMtWrSIf/3XfyWTyXD99ddPONnKttS2bbZu3TrjH3iFiz8dqchc1uJjNzYgVIRXCmhtMPjI+2ZG6ZwsgPL000/z7ne/m6997Wuzkrm8973v5Tvf+Q5KKX7+859TW1s7J9Y3s4H6+noeeughfuVXfoUtW7awdevW5DXLslizZg3Nzc1s27btlG3p2VAqlXBdd9pSkX/w+U5sERF4PguaBJ++eWYBbbIAyt69e6mqquKxxx6bFfLHpbSujuNwzz338N/+23/jxhtv5LHHHksSCsMwWLp0KUuXLmXnzp309/djnibYTYU4junr62PBggXUVplICZ4baNcWKRFxyFvWp+hoPfV+bq4FwxAcPBqUVcWkrueHZeumKTJd3/fJ5/PJ7yifz/PSSy/xzDPPzApD9lzWVZwlO5v1AcxnnnmG2267jbvuuosPfvCDEwLV2NgYe/bsYeHChXR0dJw1iFWeuKtXr06Ew6eDfQeLHDzs8mtvn1kdSinFL37xCzZs2IDjOCil2LJlC9/85jenLfhy00038dRTTyUd8vHZ/+c+9zmUUnzhC1/g8ccfJ5vN8q1vfYtNmzZBRTB2djDr6/ryyy/z8Y9/nOuvv54vfvGLE6zXXddl9+7d1NfXs3jx4mnNcu7Zs4fm5uYZuVCEkeTgEZcVS2YeJHfu3El3d3fSsLvtttu48cYb+fVf//Vpvf8iWVeY5bUdGBjg1ltvZcGCBfz5n//5hOQmDENefPFFTNNMZvLPhiNHjiClpLu7m2MDMQ//8xiFkRIn3BRu0aM2HfOVu7umvPef3xfyxM9LBJ4E2yFf1DO6KcfADyQbVznc/GsT+zOvvPIK6XQ6ESq/9957UUrx+7//+9M6/7lY13kPuqBJBZ/97GdJp9P8r//1vybMX0ZRxMsvv0wcx6xateqMddKhoSGOHTvGFVdcMRdf8xScOHGCgYEBVq9eDcDWrVv5q7/6Kx555JH5qM9d1EEXdFZx9913s3PnTr7+9a9PeOJLKTl06BBDQ0OsWbPmjDsTz/PYtWsXmzdvnpe6Z+WhUL5ZGBwc5MYbb2Tr1q3zIVR+UQdd0Gv31a9+le985zvcd999rFmz5tWDKUVfXx9Hjhxh1apVZ5x5lVLyi1/8gs2bN2NZFp6v+Np3R8mPeQzmTfxiiQ+8K8eW0yRDo8WI+39QIvAjjg8rLNPQxgQywnQcrrrc4aZ3vRp04zjm2Wef5Q1veEOZMhzx1re+laeeeuqsfYJZwGnX9YJI39fX1/Pwww9zzTXXsGXLlgkDxZVtaWtrK9u2bTsjk20+BdHh1dpQBa8ln6zZQCqV4itf+Qpf+tKXeN/73sePf/zjCdvSJUuWsGzZMnbu3Mnx48dP+zmVSZT5uq6TBVC++c1v8ulPf/o14QwxGzAMg9tvv51vfOMbfO5zn+PBBx+coCLY0dGREIgOHTp02t7GsWPHaG1tTTLidEpgEGmRG7eEiLzTBlzQeg2mpV1gglDie6F2fXZDRNk3bzz6+vomjP899thjXHPNNfMRcM+IC/arMgyDT33qUzz00EN86Utf4m/+5m8mdEtbW1tZt24dBw4cmHL2c2RkBMuy5tTccjzy+TxCiKS+d/ToUXp6enjrW986L8e/VCCEYMuWLTz55JN861vf4ktf+lLScAE9nrRx40YGBwennP30fZ/R0dFkvnuuMVkAxfM8/s//+T987GMfm5fjX0pYt24dP/nJT9izZw8333wzJ06cSF7LZrNs3LiRMAynVHObLERVQeh6jA4XKYx4vGn92e/ltKGwhcQx9ZgYEsIwwnMjDF6NH0qpsqZ2Z/Lf999//0Whi3LBH+WrVq3i6aefZmBggPe///0TMqBKk80wjAndUnjV6nu+MJntdv/99/M7v/M7r2dDp0FrayuPPvooK1euZMuWLezZsyd5zbbtCWpu43UtKlnnfGW5k7WQv//97/Oe97xnRj2C/0rIZrPcf//9fOxjH+PXf/3Xefrpp5PXDMNg+fLliZrbeF2LCgV3crkwmzEII4VjC25+/+k1eCtwzBjPC7GEwncj4qhsDSQVxdFXA/2JEyeora1NyFLbtm2jsbFx3mRIz4SLImKkUin+6q/+ijvvvJMbbriBxx9/fMLs55IlS1i+fDk7d+6kr68vGU+aD+FsOFUAJZ/P88QTT/DhD394Xo5/qcIwDO64447EyPEb3/jGhB1Le3t7si09ePAgvu8zNDREW9vZb77ZwGQtZCkl3/jGN/jCF74wL8e/VCGE4AMf+AA/+tGP+Mu//Ev+6I/+aALJqaGhgY0bN9LX18eLL75IFEWn2FlVkM2YRBLWLM+Qss/uCOs4gihS+IH2vpNhQBxL4jBm8YJXG3mTj/fVr36VO+6446IoBV4UQRf0Ql533XU88cQTPPjgg/z+7//+hC1KXV1dQkl8/vnn58XLqILJAij/8A//wE033XRayvHrmIj169fzzDPPsGvXLj760Y9O0CmubEsrTY/29vZ5uzH6+/snCKA888wzXHbZZRfV/OzFjIULF/LEE09QU1PD9ddfP4GhWJmJra6u5uc//zlVVVVT3i9VOe1vd/P7pjelUpURxLFCKgVIIi8gjhQyjslmdDgbGxvDNM2LthR40QTdCtra2vjRj37EkiVL2LJlCy+++GLymmVZdHd3Y9s2e/funfHs57lgsgBKHMd85zvf4bOf/eycH/u1hFwux4MPPsjNN9/M9ddfzzPPPJO8VpGLFELQ29tLf3//nH+fqbSQZ4sa+l8JlmXxP/7H/+Av//Iv+chHPnIKQ3HBggUYhkGhUODw4cOnNNmaG2wWtKbobJue0Wc6bSCVDlyGkKRTer63u90kl9Xh7GIvBV4c32ISDMPgd3/3d7nvvvv49Kc/zTe/+c1kW3rw4EEuu+yyKSmJc4He3l7a29uTBfvxj3/Mm9/8ZhobpyfW/DpehRCCD3/4wzz22GP8z//5PyfMPPb09LBo0SI2bdpEf38/e/bsOa14/GxgeHiYXC6XCKDs3bsXz/NYv379nB3ztYyrr76ap556iieeeGICQ3FgYICGhgauuuoqfN9nx44d+L6fvK+p3mLt6unXz6vSAgwD3/WIopgNazIIobjumiqqcyae5+G6buLccjGWAi/KoFvBxo0beeaZZ9i+fTu33HILv/zlLxkdHaW+vv60lMTZhFKK3t7eZLC6Igd3xx13zPqx/iuhq6uLJ598MmEovvDCC+zdu5cFCxYkTbba2lqee+65CfTi2cTkMbGvfe1rfPGLX7woan6XKurq6njooYd417vexZYtW3j22Wd59tln6e7uxjAMVqxYwaJFi9i+fTuDg4MAtLU4XP+O6Y9wpVIS01A0VknWrszwmd9sY8OqDJctSVGVNZNa7vhS4M0333xRlQIvCDliplBK8d3vfpf//t//O7feeuspQW94eJiXX36ZxYsXz6pTa39/PyMjI6xcuRKA7du3c8899/DDH/7wQtycFz054lzwk5/8hM9+9rNs2rSJ++67b8J1LRaL7N69m5aWllmd2y0UCuzduzexVj958iTvfe972bp16wQm3TzhoidHnAtefvllbr75ZnK5HD/60Y8mXNcgCNi9ezeZTIbly5fP6Jr/8uUS3/vRCTZdnuG9v9qEEIIwktiWgeuGPP/81oQMEccxb3nLW/j3f//3adPJZxEXFzliphBCJEPNjz/+OH/2Z382QUSlvr6ejRs30t/fz+7du6fU/TwXTNUBveuuu17PhmYRb3zjGzFNk0KhwOc+9zny+XzyWi6XY9OmTYRheMq29HwweV2/+c1v8slPfvJCBNzXLFauXEltbS0rVqzgxhtvnKAx6zgO69atI5fLzdjUoDpnUldjcd07G5P70C4L6Q4M9NLR0TGhFHj11VdfiIB7RlwSQRego6ODJ598kn/7t3/Dsize8573cPjw4eT1yra0vr6erVu3nve2dLIAyrFjxzh48CBve9vbzutzX8dE2LbNf/zHf/CDH/yAt7/97acwFCuzn5O3peeKIAjI5/NJTd73fX7wgx/wiU984rw+93WcikceeYQHH3yQ3/u93+PGG2+cwFAUQrBw4ULWrFnD7t27E+fwsyGbNXAcKwm0FUgpL5lS4CUTdEFLBlqWxZ/+6Z/y5S9/md/4jd/gBz/4wYSF7Ojo4IorruDll18+IyXxbJjcAf3617/O5z//+YumA/paQm1tLYZh8MlPfjJhKP71X//1hEZaY2MjGzdu5NixY2d0aD4benp66OzsTLKkf/zH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\n",
      "text/plain": [
       "<Figure size 432x288 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "args = Options().parse()\n",
    "args.problem = Problem()\n",
    "\n",
    "args.model = ResPINN(2, 1, dim_hidden=args.dim_hidden, res_blocks=args.res_blocks)\n",
    "args.testset = Testset(args.problem, 100, 100, method='uniform')  \n",
    "tester = Tester(args)\n",
    "tester.predict()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
